// Copyright 2008-2011 Andrey Zholos. All rights reserved.

/* globals */

var map, chat, inv, client;


/* document functions */

if (document.createElementNS) {
    function createElement(name) {
        return document.createElementNS("http://www.w3.org/1999/xhtml", name);
    }
} else {
    function createElement(name) {
        return document.createElement(name);
    }
}

function removeChildren(element) {
    while (element.firstChild)
        element.removeChild(element.firstChild);
}

function requestObject() {
    if (window.XMLHttpRequest)
        return new XMLHttpRequest();
    else if (window.ActiveXObject)
        return new ActiveXObject("Microsoft.XMLHTTP");
}

function windowSize() {
    if (window.innerWidth)
        return { width: window.innerWidth, height: window.innerHeight };
    if (document.body)
        return { width: document.body.clientWidth, height: document.body.clientHeight };
    if (document.documentElement && document.documentElement.clientWidth)
        return { width: document.documentElement.clientWidth, height: document.documentElement.clientHeight };
    return { width: 1024, height: 768 }; /* take a guess; should never happen */
}

function registerEventHandler(element, event, handler) {
    if (element.addEventListener) {
        element.addEventListener(event, handler, false);
        return { unregister: function(element, event, handler) { return function() { element.removeEventListener(event, handler, false); }; }(element, event, handler) };
    } else {
        event = "on" + event;
        handler = function(handler) { return function() { return handler(window.event); }; }(handler);
        element.attachEvent(event, handler);
        return { unregister: function(element, event, handler) { return function() { element.detachEvent(event, handler); }; }(element, event, handler)  };
    }
}

function stopEventPropagation(event) {
    if (event.stopPropagation)
        event.stopPropagation();
    else
        event.cancelBubble = true;
}

function preventEventDefault(event) {
    if (event.preventDefault)
        event.preventDefault();
    else
        event.returnValue = false;
}

function makeSize(size) {
    return typeof(size) == "number" ? Math.round(size) + "px" : size;
}

function emSize() {
    var x = "12pt";
    if (window.getComputedStyle)
        x = window.getComputedStyle(document.body || document.documentElement, null).getPropertyValue("font-size") || x;
    else if (client.body.currentStyle)
        x = client.body.currentStyle.fontSize || x;
    return parseInt(x);
}

function arrayEqual(x, y) {
    if (x.length != y.length)
        return false;
    for (var i = 0, n = x.length; i < n; i++)
        if (x[i] !== y[i])
            return false;
    return true;
}

if (!Array.prototype.indexOf)
    Array.prototype.indexOf = function(x) {
        for (var i = 0, n = this.length; i < n; i++)
            if (this[i] === x)
                return i;
        return -1;
    }

function capitalize(s) {
    return s == s.toLowerCase() ? s.charAt(0).toUpperCase() + s.substr(1) : s;
}


/* Client class */

function Client() {
    this.cookie = "";
    this.iteration = 0;
    this.refresh = 333;
    this.state = 0; /* 0 = idle, 1 = sleeping, 2 = waiting, 3 = quit */
    this.clicks = [];
}

Client.prototype.send = function(query) {
    var request = requestObject();
    setTimeout(function(session, iteration, query) { return function() {
        if (client.session == session && client.iteration == iteration && client.state == 2)
            client.send(query);
    }; }(this.session, this.iteration, query), /^http:\/\/localhost[:\/]/.test(document.location.href) ? 500 : 5000);
    setTimeout(function(session, iteration) { return function() {
        if (client.session == session && client.iteration == iteration && client.state == 2)
            client.body.style.cursor = "progress";
    }; }(this.session, this.iteration), 500);

    request.onreadystatechange = function(request, session, iteration) { return function() {
        if (client.session == session && client.iteration == iteration && request.readyState == 4 && request.status == 200) {
            map.pre();
            eval(request.responseText);
            map.post();
            chat.post();
            inv.post();
            client.post();
            client.state = 1;
            client.body.style.cursor = "";
        }
    }; }(request, this.session, this.iteration);
    request.open("GET", "althenia?" + query);
    request.setRequestHeader("Cache-Control", "no-cache");
    request.send(null);
    /*request.open("POST", "althenia");
    request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
    request.setRequestHeader("Content-Length", query.length);
    request.send(query);*/

}

Client.prototype.call = function() {
    var query = this.cookie + ":" + this.iteration + ":" + this.clicks.join(":");
    this.clicks = [];
    this.state = 2;
    this.send(query);
}

Client.prototype.start = function() {
    this.body = document.getElementsByTagName("body").item(0);
    removeChildren(this.body);
    this.html = document.getElementsByTagName("html").item(0);

    this.html.style.overflow = this.body.style.overflow = "hidden";
    this.html.style.padding = this.html.style.margin = this.body.style.padding = this.body.style.margin = 0;
    this.html.style.width = this.html.style.height = this.html.style.width = this.body.style.height = "100%";

    map.div = this.body.appendChild(createElement("div"));
    map.div.id = "map";

    chat.div = this.body.appendChild(createElement("div"));
    chat.div.id = "chat";

    inv.div = this.body.appendChild(createElement("div"));
    inv.div.id = "inv";

    registerEventHandler(this.body, "resize", this.eventResize);
    registerEventHandler(this.html, "resize", this.eventResize);
    registerEventHandler(window, "resize", this.eventResize);

    this.reset();
    this.desktopLayout();

    this.call();
}

Client.prototype.stop = function() {
    if (client.state != 3) {
        this.clicks = [ "x" ];
        this.call();
        client.state = 3;
    }
}

Client.prototype.reset = function() {
    this.clicks = [];
    this.session = (new Date).getTime();
    map.reset();
    chat.reset();
    inv.reset();
}

Client.prototype.post = function(faster) {
    var refresh = client.clicks.length ? 1 : faster ? client.refresh / 4 : client.refresh;
    if (refresh) {
        setTimeout(function(session, iteration) { return function() {
            if (client.session == session && client.iteration == iteration && client.state == 1)
                if (map.eftw)
                    client.post(true);
                else
                    client.call();
        }; }(client.session, client.iteration), refresh);
    }
}

Client.prototype.eventResize = function() {
    client.desktopLayout();
    return true;
}

Client.prototype.desktopLayout = function() {
    var size = windowSize();
    var padding = 4;

    var wp = Math.round(Math.min(size.width * 2 / 3, Math.max(size.width / 2, Math.cos(Math.PI / 12) * Math.sqrt(3) * map.rd * 25.5)));
    var hp = Math.round(Math.min(size.height * 2 / 3, Math.max(size.height / 2, Math.cos(Math.PI / 12) * Math.sin(Math.PI * 35 / 180) * Math.sqrt(3) * map.rd * 25.5 + map.rd * 4)));

    map.div.style.position = inv.div.style.position = chat.div.style.position = "absolute";
    map.div.style.top = map.div.style.left = makeSize(0);
    inv.div.style.left = chat.div.style.top = makeSize(padding - 1);
    inv.div.style.top = makeSize(hp + padding / 2 - 1);
    chat.div.style.left = makeSize(wp + padding / 2 - 1);
    chat.div.style.width = makeSize(size.width - wp - padding * 3 / 2 - 1);
    chat.div.style.height = makeSize(size.height - padding * 2 - 1);
    map.sizeS(wp + 1, hp + 1);
    inv.sizeS(wp - padding * 3 / 2 - 1, size.height - hp - padding * 3 / 2 - 1);

    map.layout();
    chat.layout();
}

Client.prototype.click = function(click) {
    if (typeof click == "object")
        for (var i = 0, n = click.length; i < n; i++)
            this.clicks.push(encodeURIComponent(click[i]));
    else
        this.clicks.push(encodeURIComponent(click));
    if (this.state != 2)
        this.call();
}


/* initialization */

client = new Client;

registerEventHandler(window, "load", function() { client.start(); });
registerEventHandler(window, "unload", function() { client.stop(); });

