var $x = {
    api: {
        url: "http://localhost:33464/api/",
        test: function () {

        }
    }
};


var wind = function (op) {
    op = def(op, {});
    this.start = def(op.start, this.start);
    this.live = def(op.live, this.live);
    this.end = def(op.end, this.end);
    this.steps = def(op.steps, this.steps);
    this.fx = def(op.fx, this.fx);
    this.fun = def(op.fun, this.fun);
    this.interval = def(op.interval, this.interval);
    this.last = def(op.last, this.last);
};
wind.prototype = {
    start: 0,
    live: 0,
    end: 0,
    steps: 100,
    interval: 10,
    fx: function (x) {
        return x;
    },
    paused: true,
    last: function (v) { },
    fun: function (v) { },
    go: function (v) {

        var x = (this.end - this.start);
        var y = this.fx(this.live);
        this.start = this.start + x * y / this.steps;
        this.end = v;
        this.live = 0;
        if (this.paused) {

            this.request(this);
        }

    },
    request: function (th) {

        if (th.live + 1 > th.steps) {
            th.last(th.end);
            th.paused = true;
            th.live = 0;
            th.start = th.end;
        }
        else {
            th.paused = false;
            var x = (th.end - th.start);
            th.live++;
            var y = th.fx(th.live);
            y = x * y / th.steps;

            this.fun(th.start + y);

            setTimeout(function () { th.request(th); }, th.interval);
        }
    }
};

var th_while = function (bet, interval) {
    th_while.iden++;
    this.interval = interval;
    this.iden = th_while.iden;
    this.bet = bet;
}
th_while.iden = 0;
th_while.prototype = {
    bet: function () { return true; },
    flag: false,
    stop: false,
    interval: 0,
    iden: 0,
    call: function (fun) {
        if (!this.iden) return;
        if (fun) this.fun = fun;
        this.flag = this.bet();
        if (this.flag) { this.fun(); } else {
            if (!this.stop) {
                var th = this;
                var func = function () { th.call() };
                setTimeout(function () { requestAnimationFrame(func); }, this.interval);
            }
        }
    },
    fun: function () { }
};


var $db = function (name, op) {
    this.name = name;
};

$db.prototype = {
    name: 'unknown',
    version: 1,
    setIndex: 0,
    set: function (ind) {
        this.setIndex = ind;
        return this;
    },
    db: null,
    tables: [{
        name: 'objs2',
        key: 'id',
        autoKey: true,
        initFields: function (obj) {
            obj.createIndex("field1", "field1", { unique: false });
        }
    }],
    def: function (tables) {
        this.tables = tables;
        return this;
    },
    initDb: function (fun) {
        var th = this;
        var request = indexedDB.open(th.name, th.version);
        request.onsuccess = function (event) {
            th.db = request.result;
            if (def(fun)) fun(th);
        }
        request.onerror = function (event) {
            console.log("IndexedDB error: " + event.target.errorCode);
        };

        request.onupgradeneeded = function (event) {
            _each(th.tables, function (obj) {
                var objectStore = event.currentTarget.result.createObjectStore(obj.name, { keyPath: obj.key, autoIncrement: obj.autoKey });
                obj.initFields(objectStore);
            });
        };
    },
    add: function (op, fun, ind) {
        var th = this;

        ind = def(ind, th.setIndex);
        if (ind != th.setIndex) th.setIndex = ind;

        var transaction = th.db.transaction([th.tables[ind].name], "readwrite");
        var objectStore = transaction.objectStore(th.tables[ind].name);
        var request = objectStore.add(op);
        request.onsuccess = function (event) {
            if (def(fun)) fun();
        };
    },
    remove: function (key, fun, ind) {
        var th = this;

        ind = def(ind, th.setIndex);
        if (ind != this.setIndex) th.setIndex = ind;

        var transaction = th.db.transaction([th.tables[ind].name], "readwrite");
        var objectStore = transaction.objectStore(th.tables[ind].name);
        var request = objectStore.delete(parseInt(key));
        request.onsuccess = function (event) {
            if (def(fun)) fun();
        };
        request.onerror = function (event) {
            console.log("error deleting record");
        };
    },
    all: function (fun, end, ind) {
        var th = this;

        ind = def(ind, th.setIndex);
        if (ind != th.setIndex) th.setIndex = ind;

        var transaction = th.db.transaction([th.tables[ind].name], "readonly");
        var objectStore = transaction.objectStore(th.tables[ind].name);
        var request = objectStore.openCursor();

        request.onsuccess = function (event) {
            var cursor = event.target.result;
            if (cursor) {
                if (def(fun)) fun(cursor.value, cursor);
                cursor.continue();
            }
            else {
                if (def(end)) end();
            }
        };
    },
    filterOnly: function (index, value, fun, end, ind) {
        var th = this;

        ind = def(ind, th.setIndex);
        if (ind != th.setIndex) th.setIndex = ind;

        var transaction = th.db.transaction([th.tables[ind].name], "readonly");
        var objectStore = transaction.objectStore(th.tables[ind].name);
        var idx = objectStore.index("by_" + index);

        var request = objectStore.openCursor(IDBKeyRange.only(value));

        request.onsuccess = function (event) {
            var cursor = event.target.result;
            if (cursor) {
                if (def(fun)) fun(cursor.value, cursor);
                cursor.continue();
            }
            else {
                if (def(end)) end();
            }
        };
    },
    first: function (index, value, fun, ind) {
        var th = this;

        ind = def(ind, th.setIndex);
        if (ind != th.setIndex) th.setIndex = ind;

        var transaction = th.db.transaction([th.tables[ind].name], "readonly");
        var objectStore = transaction.objectStore(th.tables[ind].name);
        var idx = objectStore.index(index);

        var request = idx.get(value);

        request.onsuccess = function (event) {
            var cursor = event.target.result;
            if (cursor !== undefined) {
                if (def(fun)) fun(cursor, value);
            }
            else {
                if (def(fun)) fun(null, value);
            }
        };

        request.onerror = function (event) {
            console.log("error deleting record");
        };
    },
    close: function () {
        this.db.close();
    },
    dispose: function () {
        var iDb = indexedDB.deleteDatabase(this.name);
        iDb.onsuccess = function (event) {
            //alert("database deleted");
        };
        iDb.onerror = function (event) {
            console.log("error deleting database");
        };
    },
    toBase64: function (url, callback, outputFormat) {
        var img = new Image();
        img.crossOrigin = 'Anonymous';
        img.onload = function () {
            var canvas = document.createElement('CANVAS'),
                ctx = canvas.getContext('2d'), dataURL;
            canvas.height = this.height;
            canvas.width = this.width;
            ctx.drawImage(this, 0, 0);
            dataURL = canvas.toDataURL(outputFormat);
            callback(dataURL);
            canvas = null;
        };
        img.src = url;
    }
}

var innerDb = new $db('spReqData');

innerDb.tables = [
    {
        name: 'images',
        key: 'id',
        autoKey: true,
        initFields: function (obj) {
            obj.createIndex('id', 'id', { unique: true });
            obj.createIndex('path', 'path', { unique: true });
        }
    },
    {
        name: 'script',
        key: 'id',
        autoKey: true,
        initFields: function (obj) {
            obj.createIndex('id', 'id', { unique: true });
            obj.createIndex('path', 'path', { unique: true });
        }
    },
    {
        name: 'css',
        key: 'id',
        autoKey: true,
        initFields: function (obj) {
            obj.createIndex('id', 'id', { unique: true });
            obj.createIndex('path', 'path', { unique: true });
        }
    },
    {
        name: 'html',
        key: 'id',
        autoKey: true,
        initFields: function (obj) {
            obj.createIndex('id', 'id', { unique: true });
            obj.createIndex('path', 'path', { unique: true });
        }
    }
];

window.onload = function () {
    innerDb.initDb();
};

var req = function (url, kind, end, progress) {
    this.url = url;
    this.end = end;
    this.kind = kind;
    this.progress = progress;
};
req.prototype = {
    url: '',
    kind: '',
    progress: function (l, t) { },
    end: function (v) { },
    error: function (v) { },
    get: function (cache) {
        var th = this;
        function req_go(th) {
            var req1 = new XMLHttpRequest();

            req1.addEventListener("progress", function (event) {
                if (event.lengthComputable) { th.progress(event.loaded, event.total); }
                else { th.progress(event.loaded, null); }


            }, false);

            req1.onreadystatechange = function () {


                if (this.readyState == this.DONE) {
                    if (this.status == 200) {
                        // success!
                        if (cache) {
                            try { innerDb.add({ path: th.url.toString().toLocaleLowerCase(), data: this.responseText }, null, th.kind); } catch (e) { console.log(e.message); }
                        }

                        th.end(this.responseText);
                    }
                }
            };

            req1.addEventListener("load", function (ev) {
                // th.end(ev.responseText);
            }, false);

            req1.addEventListener("error", function (event) {
                th.error(event);
            }, false);

            req1.open("GET", th.url);
            req1.send();
        }
        th.state = 0;
        new th_while(function () {

            if (cache) {
                try {
                    if (!innerDb.db) return false;
                    innerDb.first('path', th.url.toString().toLocaleLowerCase(), function (c, v) {
                        if (!c || !c.data) th.state = 1;
                        else {
                            th.state = 2; th.progress(100, 100); th.end(c.data);
                        }
                    }, th.kind);
                } catch (e) { console.log(e.message); }
            }
            else return true;

            return th.state > 0;
        }, 10).call(function () {
            if (th.state != 2)
                req_go(th);
        });

    }
};

var tit = 0;

String.prototype.api = function (op) {
    var s = this;
    dy.xhr.upload({
        url: $x.api.url + s,
        success: function (d) {
            if (op.success) {
                op.success(d);
            }
        },
        error: function (d) {
            if (op.error) {
                op.error(d);
            }
        }
    })
}

var html_parents = [];

String.prototype.AddContent = function (css, inte, op) {
     
    css = def(css, 'fadeIn');
    var css2 = 'nan';
    if (css.indexOf('!')) {
        css2 = css.split('!')[1];
        css = css.split('!')[0];
    }
    inte = def(inte, 0);

    op = def(op, {});
    var url = def(op.url, this);
    var cache = def(op.cache, _null);
 
    var par = def(op.par, _null);
    var fun = def(op.fun, _null);
    var fn = def(op.review, function (ht,i) {
        ht = ht.replace('#[Time]',
            new Date().getHours() + ' : ' +
            new Date().getMinutes() + ' : ' +
            new Date().getSeconds()
        ); return ht;
    });

    var prg = def(op.prg, function (mi, par) {
        if (first('prg', null, par)) first('prg', null, par).style.width = min(100, (mi)) + "%";
    });

    var pul = url.split("#!");

    if (pul.length > 1) pul = pul[1].valueOf() * 1024.;
    else pul = 0;
    var me = document.currentScript;

    if (!par && me) {
        par = me.parentNode;
    }
    var parIndex = -1;
    if (par) {
        html_parents.push(par);
        parIndex = html_parents.length - 1;
    }

    if (par) {
        par.classList.remove(css);
        par.classList.remove(css2);
        par.classList.add(css2);

    }
   

        var elmt = document.createElement("div");
        elmt.innerHTML = fn(url,0);

        var scripts = elmt.getElementsByTagName("script");
        var script = "";

        var loadList = [];
        _for(scripts, function (it, i) {
            if (it.src) {
                /* !!! under construction */

                loadList.push(it.src);
            }
            else {
                script += fn(it.innerHTML,1);
                it.outerHTML = "";
            }
        }, function () {

            var lf = function () {
                if (loadList.length > 0) {
                    var src = loadList.pop();
                    dy.xhr.download({
                        url: src,
                        type: 'GET',
                        success: function (d) {
                            window.eval(d);

                            requestAnimationFrame(lf);
                        },
                        error: function () {
                            requestAnimationFrame(lf);
                        }
                    })
                }
            }
            loadList = loadList.reverse();
            lf();
        });

        if (op.end) op.end();

        if (fun && !fun(me, result)) return;

        setTimeout(function () {
            if (par) {
                par.classList.remove(css2);
                par.classList.remove(css);
                par.classList.add(css);
                if (!op.append)
                    par.innerHTML = elmt.innerHTML;
                else
                    par.innerHTML += elmt.innerHTML;
            }
        }, inte * 500.);

       
        if (fun) fun(par);
    
};


String.prototype.html = function (css, inte, op) {
    // url,   cache,par, fun
    css = def(css, 'fadeIn');
    var css2 = 'nan';
    if (css.indexOf('!')) {
        css2 = css.split('!')[1];
        css = css.split('!')[0];
    }
    inte = def(inte, 0);

    op = def(op, {});
    var url = def(op.url, this);
    var cache = def(op.cache, _null);

    if (!cache)
        url += "?" + (new Date().getTime());

    var par = def(op.par, _null);
    var fun = def(op.fun, _null);
    var fn = def(op.review, function (ht,i) {
        ht = ht.replace('#[Time]',
            new Date().getHours() + ' : ' +
            new Date().getMinutes() + ' : ' +
            new Date().getSeconds()
        ); return ht;
    });

    var prg = def(op.prg, function (mi, par) {
        if (first('prg', null, par)) first('prg', null, par).style.width = min(100, (mi)) + "%";
    });

    var pul = url.split("#!");

    if (pul.length > 1) pul = pul[1].valueOf() * 1024.;
    else pul = 0;
    var me = document.currentScript;

    if (!par && me) {
        par = me.parentNode;
    }
    var parIndex = -1;
    if (par) {
        html_parents.push(par);
        parIndex = html_parents.length - 1;
    }

    if (par) {
        par.classList.remove(css);
        par.classList.remove(css2);
        par.classList.add(css2);

    }
    if (!me) me = { i: 0 };
    me.i = 0;
    var result = "";
    new req(url, 3, function (v) { me.i = 100; result = v; }, function (l, t) {
        // console.log(l + ' ' + me.i + ' ' + pul);
        if (t) me.i = l * 100. / t;
        else if (pul > 0) me.i = l * 100. / pul;
    }).get(cache);
    new th_while(function () {
        prg(me.i, par);
        return me.i == 100;
    }, 10).call(function () {

        var elmt = document.createElement("div");
         elmt.innerHTML = fn(result,0);
        
        var scripts = elmt.getElementsByTagName("script");
        var script = "";

        var loadList = [];
        _for(scripts, function (it, i) {
            if (it.src) {
                /* !!! under construction */

                loadList.push(it.src);
            }
            else {
                script += fn(it.innerHTML,1);
                it.outerHTML = "";
            }
        }, function () {

            var lf = function () {
                if (loadList.length > 0) {
                    var src = loadList.pop();
                    dy.xhr.download({
                        url: src,
                        type: 'GET',
                        success: function (d) {
                            window.eval(d);

                            requestAnimationFrame(lf);
                        },
                        error: function () {
                            requestAnimationFrame(lf);
                        }
                    })
                }
            }
            loadList = loadList.reverse();
            lf();
        });

        if (op.end) op.end();

        if (fun && !fun(me, result)) return;

        setTimeout(function () {
            if (par) {
                par.classList.remove(css2);
                par.classList.remove(css);
                par.classList.add(css);
                if (!op.append) 
                    par.innerHTML = elmt.innerHTML;
                else 
                    par.innerHTML += elmt.innerHTML;
            }
        }, inte * 500.);

        setTimeout(function () {

            if (parIndex != -1) {
                script = script
                    .replaceAll('Html_Parent', 'html_parents[' + parIndex + ']');
            }
            console.log(script);
            window.eval(script);
        }, inte * 500. + 10);

        if (fun) fun(par);
    });
};

String.prototype.jsStepLoader = function (fun, inte) {


    function loadNext(i) {
        if (i < url.length) {
            setTimeout(function () {
                dy.xhr.download({
                    url: url[i], success: function (d) { if (fun && fun(d, url[i+1],!( i+2 < url.length))) window.eval(d); }, end: function () {

                        loadNext(i + 2);
                    }
                });
            }, inte);
        }
    };

    var url = this.split(',');
    loadNext(0);

};


String.prototype.img = function (cls, css, inte, op) {
    // url,   cache,par, fun
    css = def(css, 'fadeIn');
    var css2 = 'nan';
    if (css.indexOf('!')) {
        css2 = css.split('!')[1];
        css = css.split('!')[0];
    }
    inte = def(inte, 0);

    op = def(op, {});
    var url = def(op.url, this);
    var cache = def(op.cache, _null);

    if (!cache)
        url += "?" + (new Date().getTime());

    var par = def(op.par, _null);
    var fun = def(op.fun, _null);
    var fn = def(op.review, function (ht) {
        ht = ht.replace('#[Time]',
            new Date().getHours() + ' : ' +
            new Date().getMinutes() + ' : ' +
            new Date().getSeconds()
        ); return ht;
    });

    var prg = def(op.prg, function (mi, par) {
        if (first('prg', null, par)) first('prg', null, par).style.width = min(100, (mi)) + "%";
    });

    var pul = url.split("#!");

    if (pul.length > 1) pul = pul[1].valueOf() * 1024.;
    else pul = 0;
    var me = document.currentScript;

    if (!par && me) {
        par = me.parentNode;
    }
    var parIndex = -1;
    if (par) {
        html_parents.push(par);
        parIndex = html_parents.length - 1;
    }

    if (par) {
        par.classList.remove(css);
        par.classList.remove(css2);
        par.classList.add(css2);

    }
    if (!me) me = { i: 0 };
    me.i = 0;
    var result = "";
    new req(url, 3, function (v) { me.i = 100; result = v; }, function (l, t) {
        // console.log(l + ' ' + me.i + ' ' + pul);
        if (t) me.i = l * 100. / t;
        else if (pul > 0) me.i = l * 100. / pul;
    }).get(cache);
    new th_while(function () {
        prg(me.i, par);
        return me.i == 100;
    }, 10).call(function () {

        var img = document.createElement("img");
        img.className = cls;
        img.onload = function () {
            setTimeout(function () {
                console.log(par);
                if (par) {
                    par.classList.remove(css2);
                    par.classList.remove(css);
                    par.classList.add(css);
                    par.innerHTML = "";
                    par.appendChild(img);
                }

                if (fun) fun(par);
            }, inte * 500.);

        }
        img.src = url;

    });
};
