/*
 *  Copyright 2007 hkrn <hikarin@users.sourceforge.jp>
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 * Zeromin
 * $Id: zeromin.js 242 2007-02-15 14:38:31Z hikarin $
 */

function login() {
    var user = $("//input[@name='userName']").val();
    var pass = $("//input[@name='userPass']").val();
    var loginError = $(document.getElementById("loginError"));
    loginError.hide();

    if (!user) {
        loginError.html("ユーザー名が入力されていません").show();
        return;
    }
    else if (!pass) {
        loginError.html("パスワードが入力されていません").show();
        return;
    }
    else {
        var process = $(document.getElementById("loginProcess"));
        loginError.hide();
        process.html("認証中です...").show();
        var io = new Zeromin.IO(ZEROMIN_CGI_URI, user, pass);
        io.load(
            [ { "name": "uv", "value": 1 } ],
            function (rs) {
                try {
                    if ( rs["ok"] && rs["loginOK"] ) {
                        $(document.getElementById("loggedUser")).html(user);
                        process.html("カテゴリ一覧を取得中です...");
                        io.load(
                            [
                                { "name": "C", "value": "category" },
                                { "name": "M", "value": "load" }
                            ],
                            function(storage) {
                                var cat = new Zeromin.Category(
                                    storage.getRawData().content
                                );
                                Zeromin.setInstance("Category", cat);
                                Zeromin.setInstance("IO", io);
                                var bbs = new Zeromin.BBS();
                                process.html("掲示板一覧を取得中です...");
                                bbs.load();
                                Zeromin.setInstance("BBS", bbs);
                            },
                            null,
                            false
                        );
                    }
                    else {
                        process.hide();
                        var str = "ユーザー名またはパスワードが違います";
                        loginError.html(str).show();
                    }
                } catch(e) {
                    process.hide();
                    var str = "例外が発行されました<br />["
                        + e.name + "] " + ( e.description || e.message );
                    loginError.html(str).show();
                }
            },
            null,
            true
        );
    }
}

/*
if ( typeof console == "undefined" ) {
    var console = {
        "log": function() {},
        "debug": function() {}
    };
}
*/

var Zeromin = {
    "instances": {},
    "intval": function(val) {
        val = parseInt(val);
        return isNaN(val) ? 0 : val;
    },
    "getInstanceOf": function(className) {
        var instance = this.instances[className];
        return !instance ? null : instance;
    },
    "setInstance": function(className, object) {
        this.instances[className] = object;
        return;
    },
    "getArchive": function() {
        return this.getInstanceOf("Archive");
    },
    "getBanner": function() {
        var banner = this.getInstanceOf("Banner")
        if ( !banner ) {
            banner = new Zeromin.Banner();
            this.setInstance("Banner", banner);
        }
        return banner;
    },
    "getBBS": function() {
        return this.getInstanceOf("BBS");
    },
    "getCap": function() {
        var cap = Zeromin.getInstanceOf("Cap")
        if ( !cap ) {
            cap = new Zeromin.Cap();
            this.setInstance("Cap", cap);
        }
        return cap;
    },
    "getCategory": function() {
        return this.getInstanceOf("Category");
    },
    "getCgroup": function() {
        var cgroup = this.getInstanceOf("Cgroup")
        if ( !cgroup ) {
            cgroup = new Zeromin.Cgroup();
            this.setInstance("Cgroup", cgroup);
        }
        return cgroup;
    },
    "getFilterIP": function() {
        var filterIP = this.getInstanceOf("Filter.IP");
        if ( !filterIP ) {
            filterIP = new Zeromin.Filter.IP();
            this.setInstance("Filter.IP", filterIP);
        }
        return filterIP;
    },
    "getFilterHost": function() {
        var filterHost = this.getInstanceOf("Filter.Host");
        if ( !filterHost ) {
            filterHost = new Zeromin.Filter.Host();
            this.setInstance("Filter.Host", filterHost);
        }
        return filterHost;
    },
    "getFilterNGWord": function() {
        var filterNGWord = this.getInstanceOf("Filter.NGWord");
        if ( !filterNGWord ) {
            filterNGWord = new Zeromin.Filter.NGWord();
            this.setInstance("Filter.NGWord", filterNGWord);
        }
        return filterNGWord;
    },
    "getIO": function() {
        return this.getInstanceOf("IO");
    },
    "getLogAction": function() {
        var action = this.getInstanceOf("Log.Action")
        if ( !action ) {
            action = new Zeromin.Log.Action();
            this.setInstance("Log.Action", action);
        }
        return action;
    },
    "getLogError": function() {
        return this.getInstanceOf("Log.Error");
    },
    "getLogThread": function() {
        return this.getInstanceOf("Log.Thread");
    },
    "getMetadata": function() {
        return this.getInstanceOf("Metadata");
    },
    "getPlugin": function( bbs, id ) {
        var plugin = this.getInstanceOf("Plugin");
        if ( !plugin ) {
            plugin = new Zeromin.Plugin();
            this.setInstance("Plugin", plugin);
        }
        if ( id != null && bbs != null ) {
            plugin.setBBS(id, bbs);
        }
        return plugin;
    },
    "getPool": function() {
        return this.getInstanceOf("Pool");
    },
    "getSetting": function() {
        return this.getInstanceOf("Setting");
    },
    "getSubject": function() {
        return this.getInstanceOf("Subject");
    },
    "getSystem": function() {
        var system = this.getInstanceOf("System")
        if ( !system ) {
            system = new Zeromin.System();
            this.setInstance("System", system);
        }
        return system;
    },
    "getThread": function() {
        return this.getInstanceOf("Thread");
    },
    "getUgroup": function() {
        var ugroup = this.getInstanceOf("Ugroup")
        if ( !ugroup ) {
            ugroup = new Zeromin.Ugroup();
            this.setInstance("Ugroup", ugroup);
        }
        return ugroup;
    },
    "getUser": function() {
        var user = this.getInstanceOf("User")
        if ( !user ) {
            user = new Zeromin.User();
            this.setInstance("User", user);
        }
        return user;
    },
    "getDate": function(epoch) {
        var date = new Date(Number(epoch + "000"));
        var string = date.getFullYear() + "年 "
            + (date.getMonth() + 1) + "月"
            + date.getDate() + "日 "
            + date.getHours() + ':'
            + date.getMinutes() + ':'
            + date.getSeconds();
        return string;
    }
};

Zeromin.DOM = {
    "hideLink": "<a href=\"javascript:void(0)\" "
        + "onclick=\"$('div.State').hide()\">×</a>&nbsp;",
    "primary": false,
    "statusOK": function(message, wait) {
        if ( this.primary ) {
            this.primary = false;
            return;
        }
        var css     = {
            "background":   "#eeffee",
            "border-color": "#99ff99",
            "color":        "green"
        };
        var state   = $("div.State");
        state.css(css).html(this.hideLink + message).show();
    },
    "statusNG": function(message, wait) {
        var css = {
            "background":   "#ffeeee",
            "border-color": "#ff9999",
            "color":        "red"
        };
        var state = $("div.State");
        var error = this.hideLink.replace(
            "a href", "a class='closeErrorStatus' href"
        ) + message;
        this.primary = true;
        state.css(css).html(error).show();
        $(document.getElementById("loginProcess")).hide();
        $(document.getElementById("loginError")).html(error).show();
    },
    "changePage": function(root) {
        $(".Container", document).hide();
        $(root).show();
    },
    "checkAll": function(where) {
        $(where).find("input").each(function(){
            this.checked = true;
        });
    },
    "deserialize": function(param) {
        var found = {};
        var props = {};
        for ( var i in param ) {
            var name  = param[i].name;
            var value = param[i].value;
            if ( found[name] > 0 ) {
                if ( found[name] == 1 ) {
                    props[name] = [ props[name], value ];
                }
                else {
                    props[name].unshift(value);
                }
            }
            else {
                props[name] = value;
            }
            if ( !found[name] ) found[name] = 0;
            found[name]++;
        }
        return props;
    },
    "disableMethodSelector": function() {
        $("//select[@name='M']").attr({ "disabled": true });
    },
    "enableMethodSelector": function() {
        $("//select[@name='M']").attr({
            "disabled": false
        });
    },
    "escapeHTML": function(string) {
        return string.replace(
            /&/g, "&amp;"
        ).replace(
            /</g, "&lt;"
        ).replace(
            />/g, "&gt;"
        ).replace(
            /"/g, "&quot;"
        ).replace(
            /'/g, "&#39;"
        );
    },
    "fillForm": function(root, item, option) {
        $("input,select", root).each(function () {
            var t  = this.type;
            var cb = option[t + "-callback"];
            if ( cb ) return cb(item, this);
            switch (t) {
                case "text":
                case "hidden":
                var val = item[this.name];
                if ( val == null ) return;
                $(this).val(val);
                break;
                case "select-one":
                case "select-multiple":
                var val = item[this.name];
                var opt = this.options;
                var len = option.length;
                for (var i = 0; i < len; i++) {
                    var o = opt[i];
                    o.selected = false;
                    o.selected |= (o.value == val);
                }
                break;
            }
        });
    },
    "getRemoteHost": function( element, event, ip ) {
        var buildTooltip = function(rs) {
            var content = ip + " <=> " + rs.resolved
                + " (" + rs.country + ")<br>";
            var dnsbl = rs.listed;
            for ( var i in dnsbl ) {
                content += dnsbl[i] ? "×" : "○";
                content += ' ' + i + "<br>";
            }
//            console.log([element, event]);
            domTT_activate(
                element, event, "content",
                content, "type", "velcro"
            );
        }
        if ( !this.seen ) this.seen = {};
        var cache = this.seen[ip];
        if (cache) {
            buildTooltip(cache);
            return;
        }
        var self = this;
        Zeromin.getIO().load(
            [
                { "name" : "C",  "value": "log"    },
                { "name" : "M",  "value": "lookup" },
                { "name" : "ip", "value": ip       }
            ],
            function (storage) {
                var rs = storage.get("content");
                if (rs) {
                    self.seen[ip] = rs;
                    buildTooltip(rs);
                    Zeromin.DOM.statusOK("DNS情報を検索しました", 1000);
                }
            },
            null
        );
    },
    "hideState": function() {
        $("div.State").fadeOut();
    },
    "makeBreadClum": function(range) {
        var content = "<a href='javascript:Zeromin.getBBS().load()'>メインメニュー</a>"
            + " &gt; <a href='javascript:Zeromin.getBBS().load()'>掲示板全体</a>";
        var breadClum = $("div.Bread");
        switch(range) {
            case "thread":
            var bbs = Zeromin.getBBS().getName();
            var subject = Zeromin.getThread().getSubject();
            content += " &gt; <a href='javascript:Zeromin.getSubject().load()'>"
                + bbs + "</a> &gt; <a href='javascript:Zeromin.getThread().load()'>"
                + subject + "</a>";
            break;
            case "bbs":
            var bbs = Zeromin.getBBS().getName();
            content += " &gt; <a href='javascript:Zeromin.getSubject().load()'>"
                + bbs + "</a>";
            break;
        }
        content += "<br><br>";
        breadClum.html(content);
        return;
    },
    "makePager": function(dom, entries_per_page) {
        /*
         * テーブルの中身が無い時tableSorter()から例外が発行されるのでこれを無視する
         */
        try {
            dom.tableSorter({ "disableHeader": 0 })
            .pager(entries_per_page)
            .unbind("sortStop")
            .sortStop(function () { $(this).pager(entries_per_page) });
        }
        catch (e) { }
    },
    "renderLeftMenu": function(domID) {
        var container = document.getElementById("leftContainer");
        $(container).hide().find("div").hide();
        $(document.getElementById(domID)).show();
        $(container).show();
    },
    "resetForm": function(where) {
        $("input,textarea,select", where).each(function() {
            var t = this.type;
            if ( t == "text" || t == "password" ) {
                this.value = "";
                return;
            }
            if ( t == "checkbox" || t == "radio" ) {
                this.checked = false;
                return;
            }
            if (t == "select-multiple") {
                $("option:selected", this).each( function() {
                    this.selected = false;
                });
                return;
            }
        });
    },
    "revertAll": function(where) {
        $(where).find("input").each(function(){
            this.checked = false;
        });
    },
    "setFunction": function(name) {
        $(document.getElementById("globalMethodName")).html(name);
    },
    "toggleMenu": function(range) {
        this.makeBreadClum(range);
        var menuCtx = document.getElementById("menuContext");
        $("div", menuCtx).hide();
        var selectFrom = 'div#' + range + "Menu";
        $(selectFrom, menuCtx).show();
    }
};

Zeromin.IO = function(url, user, pass, timeout) {
    this.url          = url;
    this.user         = user;
    this.pass         = pass;
    this.hasConnected = false;
    $.ajaxTimeout(timeout || 15000);
};

Zeromin.IO.prototype = {
    "load": function(param, callback, self, noEval) {
        var success;
        if ( self != null ) {
            var cache = self.getCache();
            if ( cache != null) {
                var type  = cache.constructor;
                if ( ( type == Object || type == String
                    || ( type == Array && cache.length ) ) ) {
                   var storage = new Zeromin.IO.Storage(null, self, true);
                   callback(storage);
                   return;
                }
            }
        }

        $("div.State").css({
            "background":   "#eeeeff",
            "border-color": "#9999ff",
            "color":        "blue"
        }).html("読み込み中...").show();
        if (noEval) {
            success = function(responseText) { callback(responseText) };
        }
        else {
            success = function(rs) {
                try {
                    callback(new Zeromin.IO.Storage( rs, self, false ));
                } catch(e) {
                    Zeromin.DOM.statusNG(
                        "[" + e.name + "] "
                        + ( e.description || e.message )
                        + "<p>" + rs + "</p>"
                    );
                    Zeromin.DOM.enableMethodSelector();
                }
            }
        }
        var failure = function( xml, status, e ) {
            Zeromin.DOM.statusNG(
                "[" + e.name + "] "
                + ( e.description || e.message )
                + "<p>" + xml.responseText + "</p>"
            );
            Zeromin.DOM.enableMethodSelector();
        };
        param.push({ "name": "I",  "value": this.user });
        param.push({ "name": "P",  "value": this.pass });
        param.push({ "name": "js", "value": 1 });
        $.ajax({
            "data": param,
            "dataType": "json",
            "error": failure,
            "global": false,
            "success": success,
            "type": "POST",
            "url": this.url
            });
    },
    "upload": function(formId, callback) {
        var success = function(res) {
            try {
                var rs;
                eval("rs = " + res.replace(
                    /^<[^>]+>/, "" ).replace( /<[^>]+>$/, "" ));
                callback(new Zeromin.IO.Storage( rs, self, false ));
            } catch(e) {
                console.log(e);
                Zeromin.DOM.statusNG(
                    "[" + e.name + "] "
                    + ( e.description || e.message )
                    + "<p>" + rs + "</p>"
                );
                Zeromin.DOM.enableMethodSelector();
            }
        }
        var failure = function( xml, status, e ) {
            Zeromin.DOM.statusNG(
                "[" + e.name + "] "
                + ( e.description || e.message )
                + "<p>" + xml.responseText + "</p>"
            );
            Zeromin.DOM.enableMethodSelector();
        };
        $("div.State").css({
            "background":   "#eeeeff",
            "border-color": "#9999ff",
            "color":        "blue"
        }).html("読み込み中...").show();
        var formDOM = document.getElementById(formId);
        $( "input[@name='I']",  formDOM ).val(this.user);
        $( "input[@name='P']",  formDOM ).val(this.pass);
        $( "input[@name='js']", formDOM ).val('1');
        /* for jQuery 1.1 compatiblity */
        jQuery.ajaxSettings = {
            "global": true,
            "type": "GET",
            "timeout": 0,
            "contentType": "application/x-www-form-urlencoded",
            "processData": true,
            "async": true,
            "data": null
        };
        jQuery.handleError = function(s, xml, status, e ) {
            // If a local callback was specified, fire it
            if ( s.error ) s.error( xml, status, e );
            // Fire the global callback
            if ( s.global )
                jQuery.event.trigger( "ajaxError", [xml, s, e] );
        };
        $.ajaxUpload({
            "dataType": "text",
            "error": failure,
            "global": false,
            "secureuri": false,
            "success": success,
            "type": "POST",
            "uploadform": formDOM,
            "url": this.url
            });
    }
};

Zeromin.IO.Storage = function(res, self, isCached) {
    if ( res ) {
       var rawData   = res.data;
       this.rawData  = rawData;
       this.code     = Zeromin.intval(rawData.code);
       this.isOK     = Zeromin.intval(res.ok);
       this.isValid  = Zeromin.intval(res.loginOK);
    }
    else {
       this.rawData  = { "code": -1,  "data": "" };
       this.code     = -1;
       this.isOK     = 0;
       this.isValid  = 0;
    }
    this.isCache     = isCached;
    this.cacheObject = self;
};

Zeromin.IO.Storage.prototype = {
    "getCode": function () { return this.code },
    "getRawData": function () { return this.rawData },
    "isCached": function () { return this.isCache },
    "isNull": function () { return this.rawData == null },
    "isReturnedSuccess": function () { return this.code == 0 },
    "get": function(key) {
        return this._check(function() {
            return key == null ? this.rawData
               : this.rawData[ key ];
        }, null, false);
    },
    "read": function () {
        if ( this.isCache ) {
            return this.cacheObject.getCache();
        }
        else {
           return this._check(function() {
                var rawData = this.rawData.content;
                var cache = this.cacheObject;
                if (cache) cache.setCache(rawData);
                return rawData;
           }, [], false);
        }
    },
    "slurp": function () {
        if ( this.isCache ) {
            return this.cacheObject.getCache();
        }
        else {
            return this._check(function() {
                var rawData = this.rawData;
                var cache = this.cacheObject;
                if (cache) cache.setCache(rawData);
                return rawData;
            }, null, true);
        }
    },
    "writeResult": function(key, messages) {
        if ( !this.isNull() ) {
            var res = this.rawData;
            if ( typeof res == "object" ) {
                Zeromin.DOM.statusOK(messages[key]);
            }
            else {
                Zeromin.DOM.statusNG(String(res).replace(/\n/g, "<br />"));
            }
        }
    },
    "writeStatus": function(success, failed) {
        if ( !failed ) failed = [];
        failed[1] = "実行権限がありません";
        if ( this.code == 0 ) {
            Zeromin.DOM.statusOK(success || '', 1000);
        }
        else {
            Zeromin.DOM.statusNG(failed[this.code]
                || "不明なエラーです<br /><br />" + this.rawData);
        }
    },
    "_check": function(callback, returnType, noCodeCheck) {
        if ( this.isOK == 0 ) {
            var error = this.rawData;
            Zeromin.DOM.statusNG(
                "例外が発生しました<br />"
                + error.replace(/\n/g, "<br />")
            );
            return returnType;
        }
        else if ( this.isValid == 0 ) {
            Zeromin.DOM.statusNG("不正な認証です");
            return returnType;
        }
        else if ( noCodeCheck == false && this.code != 0  ) {
            Zeromin.DOM.statusNG("権限不足または送信した値が不正です");
            return returnType;
        }
        else {
            return callback.apply(this);
        }
    }
};
