/**
 * Created by liutiantian on 2015.12.22.
 */
var ltt = ltt || {};
ltt.api = ltt.api || {};
ltt.api.js = ltt.api.js || {};
ltt.api.js.ui = ltt.api.js.ui || {};

ltt.api.js.ui.View = function(html) {
    this.html = html;

    if(ltt.api.js.ui.View.initialized == undefined) {
        ltt.api.js.ui.View.prototype.getHtml = function(id, html) {
            if(id == undefined) {
                return this.html;
            }
            else {
                if(html) {
                    if(html.id == id) {
                        return html;
                    }
                    if(html.children) {
                        for(var i = 0; i < html.children.length; ++i) {
                            var res = ltt.api.js.ui.View.prototype.getHtml.call(this, id, html.children[i]);
                            if(res) {
                                return res;
                            }
                        }
                    }
                }
            }
        };

        ltt.api.js.ui.View.prototype.getHtmlNode = function(html) {
            if(html) {
                if(html.deleted) {
                    return;
                }
                var before = this.beforeNodeCreate( html);
                if(before) {
                    this.onNodeCreated(before, html);
                    return before;
                }
                var node = document.createElement(html.tag);
                node.id = html.id;
                node.className = this.classmaker.call(this, html);
                if (html.style) {
                    node.style = html.style;
                }
                if (html.children) {
                    for (var i = 0; i < html.children.length; ++i) {
                        var sub_node = ltt.api.js.ui.View.prototype.getHtmlNode.call(this, html.children[i]);
                        sub_node && node.appendChild(sub_node);
                    }
                }
                if (html.content) {
                    if(/@string[^$]+/g.test(html.content)) {
                        node.innerHTML = this.stringGet(html.content.slice(8));
                    }
                    else {
                        node.innerHTML = html.content;
                    }
                }
                this.onNodeCreated(node, html);
                return node;
            }
        };

        ltt.api.js.ui.View.initialized = true;
    }

    if(this.constructor.initialized == undefined) {
        this.constructor.prototype.classmaker = function() {
            throw new Error("you must override the classmaker method, or else the logic will crash.");
        };

        this.constructor.prototype.stringGet = function() {
            throw new Error("you must override the stringGet method, or else the logic will crash.");
        };

        this.constructor.prototype.beforeNodeCreate = function(html) {

        };

        this.constructor.prototype.onNodeCreated = function(node, html) {

        };

        this.constructor.prototype.befShow = function() {

        };

        this.constructor.prototype.aftShow = function() {

        };

        this.constructor.prototype.aftHide = function() {

        };

        this.constructor.prototype.getHtml = function(id, html) {
            return ltt.api.js.ui.View.prototype.getHtml.call(this, id, html || this.html);
        };

        this.constructor.prototype.createHtml = function(tag, id, classes, state, content, flag) {
            var html = {};
            html.tag = tag;
            html.id = id;
            html.classes = classes;
            if(content) html.content = content;
            if(flag) html.flag = flag;
            html.state = state;
            return html;
        };

        this.constructor.prototype.getHtmlNode = function(html) {
            return ltt.api.js.ui.View.prototype.getHtmlNode.call(this, html || this.html);
        };

        this.constructor.prototype.show = function() {
            this.befShow();
            try {
                var self = document.getElementById(this.html.id);
                var node = this.getHtmlNode();
                if(self) {
                    self.parentNode.replaceChild(node, self);
                    return;
                }
                document.body.appendChild(node);
            }
            finally {
                this.aftShow();
            }
        };

        this.constructor.prototype.rewrite = function(id) {
            if(id) {
                var current = document.getElementById(id);
                if(current) {
                    var html = this.getHtml(id);
                    if(html) {
                        var node = this.getHtmlNode(html);
                        if(node) {
                            current.parentNode.replaceChild(node, current);
                            this.aftShow(node, current);
                        }
                    }
                }
            }
            else {
                this.rewrite(this.html.id);
            }
        };

        this.constructor.prototype.setState = function(id, state) {
            if(id && state) {
                var html = this.getHtml(id);
                if(html) {
                    html.state = state;
                    var current = document.getElementById(id);
                    if(current) {
                        current.className = this.classmaker.call(this, html);
                    }
                }
            }
        };

        this.constructor.prototype.deleteNode = function(id, deleted) {
            var html = this.getHtml(id);
            if(html) {
                if(deleted) {
                    html.deleted = deleted;
                }
                else {
                    delete html.deleted;
                }
            }
        };

        this.constructor.prototype.hide = function() {
            var self = document.getElementById(this.html.id);
            if(self) {
                self.parentNode.removeChild(self);
                this.aftHide();
            }
        };
    }
};

/**
 * ViewGroup is a View, it can degenerate to View smoothly if it has no child view.
 * ViewGroup can only have child in its direct child position.
 * if not, ViewGroup must be contained by another ViewGroup, which means nested ViewGroup.
 * @param html
 * @constructor
 */
ltt.api.js.ui.ViewGroup = function(html) {
    ltt.api.js.ui.View.call(this, html);

    if(ltt.api.js.ui.ViewGroup.initialized == undefined) {

        ltt.api.js.ui.ViewGroup.prototype.reset = function(id, html) {
            if(this.views) {
                if(html) {
                    for(var vi = 0; vi < this.views.length; ++vi) {
                        if(this.views[vi].id == html.id) {
                            this.views[vi].attached = false;
                            break;
                        }
                    }
                    if(html.children) {
                        for(var ci = 0; ci < html.children.length; ++ci) {
                            ltt.api.js.ui.ViewGroup.prototype.reset.call(this, id, html.children[ci]);
                        }
                    }
                }
                else {
                    if(id) {
                        html = ltt.api.js.ui.View.prototype.getHtml.call(this, id);
                        if(html) {
                            ltt.api.js.ui.ViewGroup.prototype.reset.call(this, id, html);
                        }
                    }
                    else {
                        ltt.api.js.ui.ViewGroup.prototype.reset.call(this, this.html.id, this.html);
                    }
                }
            }
        };

        ltt.api.js.ui.ViewGroup.initialized = true;
    }

    if(this.constructor.initialized == undefined) {
        this.constructor.prototype.stringGet = function() {

        };

        this.constructor.prototype.addView = function(view, id, index) {
            if(view) {
                this.views = this.views || [];
                if(index == undefined || index == -1 || this.views.length <= index) {
                    this.views.push({"view": view, "id": id || this.getDefaultAttachId()});
                }
                else {
                    this.views.splice(index, 0, {"view": view, "id": id || this.getDefaultAttachId()});
                }
            }
        };

        this.constructor.prototype.getDefaultAttachId = function(html) {
            if(html) {
                if(html.children) {
                    if(html.children.length > 1) {
                        throw new Error("If your html has branches, you should pass id parameter when you call addView, or you can override this method, return the default id you want to attach.");
                    }
                    return this.getDefaultAttachId(html.children[0]);
                }
                return html.id;
            }
            else {
                return this.getDefaultAttachId(this.html);
            }
        };

        this.constructor.prototype.getHtml = function(id, html) {
            var res = ltt.api.js.ui.View.prototype.getHtml.call(this, id, html);
            if(res) {
                return res;
            }
            else if(this.views && Object.keys(this.views).length) {
                for(var vi = 0; vi < this.views.length; ++vi) {
                    res = this.views[vi].view.getHtml(id);
                    if(res) {
                        return res;
                    }
                }
            }
        };

        /**
         * this method should never be override, be careful.
         * @param html
         * @returns {*}
         */
        this.constructor.prototype.beforeNodeCreate = function(html) {
            if(this.views && Object.keys(this.views).length) {
                for(var vi = 0; vi < this.views.length; ++vi) {
                    if(this.views[vi].attached) {
                        continue;
                    }
                    if(html.id == this.views[vi].id) {
                        this.views[vi].attached = true;
                        return this.views[vi].view.getHtmlNode();
                    }
                }
            }
        };

        this.constructor.prototype.rewrite = function(id) {
            if(id) {
                ltt.api.js.ui.ViewGroup.prototype.reset.call(this, id);

                var current = document.getElementById(id);
                if(current) {
                    var html = this.getHtml(id);
                    if(html) {
                        var node = this.getHtmlNode(html);
                        if(node) {
                            current.parentNode.replaceChild(node, current);
                        }
                    }
                }
            }
            else {
                this.rewrite(this.html.id);
            }
        };

        this.constructor.prototype.removeChild = function(id, view) {
            if(this.views && Object.keys(this.views).length) {
                var views = [];
                for(var vi = 0; vi < this.views.length; ++vi) {
                    var ide = id == undefined || this.views.id == id;
                    var vie = view == undefined || this.views.view == view;
                    if(ide || vie) {
                        continue;
                    }
                    views.push(this.views[vi]);
                }
                if(this.views == views) {
                    return;
                }
                this.views = views;
                this.rewrite(id);
            }
        };

        this.constructor.prototype.replaceChild = function(newChild, id) {
            if(newChild && id) {
                if(this.views && Object.keys(this.views).length) {
                    for(var vi = 0; vi < this.views.length; ++vi) {
                        if(this.views[vi].id == id) {
                            if(newChild != this.views[vi].view) {
                                this.views[vi].view = newChild;
                                this.views[vi].attached = true;
                                this.rewrite(id);
                                return;
                            }
                        }
                    }
                }
            }
        };
    }
};
