﻿/// <reference path="MicrosoftLibrary.js" />

/*
/// <summary></summary>
/// <param name="void"></param>
/// <returns>void</returns>
*/

/// <summary>Vårat root namespace</summary>
window.Capitex = { __namespace: true, __typeName: "Capitex", getName: function() { return "Capitex" }, __upperCaseTypes: {} }
Capitex.__rootNamespaces = [Capitex];

/// <summary>Lägger till ett objekt i arrayen</summary>
/// <param name="item">objektet som ska läggas till</param>
Array.prototype.add = function(item) {
    Array.add(this, item);
}

/// <summary>Tar bort ett objekt från arrayen</summary>
/// <param name="item">objektet som ska tas bort </param>
Array.prototype.remove = function(item) {
    Array.remove(this, item);
}

/// <summary>Kontrollerar om en sträng är tom</summary>
/// <param name="str">Strängen som ska kontrolleras</param>
/// <returns>En boolean som indikerar ifall strängen är tom</returns>
String.isNullOrEmpty = function(str) { return typeof str === "undefined" || str === null || str === ""; }

/// <summary>Skriver ut ett debug meddelande sist på sidan</summary>
/// <param name="message">Meddelandet som ska skrivas ut</param>
/// <returns>void</returns>
document.writeDebug = function(message) {
    document.body.innerHTML += message;
}

/// <summary>Skriver ut alla fält och metoder på ett objekt</summary>
/// <param name="obj">Objektet som undersökas</param>
/// <param name="inline">Om objektet ska skrivas ut på anropningsplatsen</param>
/// <returns>void</returns>
document.writeObject = function(obj, inline) {
    var message = "<table class='debugObjectTable'>";
    for (var item in obj)
        message += "<tr class='debugObjectRow'><td class='debugObjectColumnId'>" + String(item) + "</td><td class='debugObjectColumnValue'>" + obj[item] + "</td></tr>";

    message += "</table>\r\n";

    if (inline)
        document.write(message);
    else
        document.body.innerHTML += message;
}

/// <summary>Klass som representerar en delegatlista för eventhantering</summary>
Capitex.EventDelegateList = function() {
    this.items = [];
}

/// <summary>Lägger till en delegat i listan</summary>
/// <param name="instance">Instansen som metoden ligger i</param>
/// <param name="method">Metoden som ska anropas</param>
/// <returns>Objektet som lades till</returns>
Capitex.EventDelegateList.prototype.add = function(instance, method) {
    var item = new Capitex.DelegateItem(instance, method);
    this.items[this.items.length] = item;
    return item;
}

/// <summary>Tar bort en delegat i listan</summary>
/// <param name="instance">Instansen som metoden ligger i</param>
/// <param name="method">Metoden som ska anropas</param>
/// <returns>void</returns>
Capitex.EventDelegateList.prototype.remove = function(instance, method) {
    var index = this.indexOf(instance, method);
    if (index >= 0)
        this.removeAt(index);
}

/// <summary>Tar bort en delegat i listan</summary>
/// <param name="item">Delegatitemet som ska tas bort</param>
/// <returns>void</returns>
Capitex.EventDelegateList.prototype.removeItem = function(item) {
    for (var index = 0; index < this.items.length; index++) {
        if (this.items[index] === item) {
            this.removeAt(index);
            return;
        }
    }
}

/// <summary>Tar bort en delegat i listan</summary>
/// <param name="index">Indexet på delegaten som ska tas bort</param>
/// <returns>void</returns>
Capitex.EventDelegateList.prototype.removeAt = function(index) {
    this.items.splice(index, 1);
}

/// <summary>Letar upp en delegat i listan baserat på metoden som ska anropas</summary>
/// <param name="instance">Instansen som metoden ligger i</param>
/// <param name="method">Metoden som ska anropas</param>
/// <returns>Delegaten</returns>
Capitex.EventDelegateList.prototype.find = function(instance, method) {
    var index = this.indexOf(instance, method);
    if (index >= 0)
        return this.items[index];
    else
        return null;
}

/// <summary>Letar upp en delegat i listan baserat på metoden som ska anropas</summary>
/// <param name="instance">Instansen som metoden ligger i</param>
/// <param name="method">Metoden som ska anropas</param>
/// <returns>Indexet där delegaten ligger i listan</returns>
Capitex.EventDelegateList.prototype.indexOf = function(instance, method) {
    var item;
    for (var index = 0; index < this.items.length; index++) {
        item = this.items[index];
        if (item.instance === instance && item.method === method)
            return index;
    }
    return -1;
}

/// <summary>Lägger till en eventhanterare för ett event</summary>
/// <param name="element">Elementet som innehåller eventet</param>
/// <param name="eventName">Namnet på eventet</param>
/// <param name="instance">Instansen som metoden ligger i</param>
/// <param name="method">Metoden som ska anropas</param>
/// <returns>void</returns>
Capitex.EventDelegateList.prototype.addHandler = function(element, eventName, instance, method) {
    var item = this.add(instance, method);
    $addHandler(element, eventName, item.delegate);
}

/// <summary>Tar bort en eventhanterare för ett event</summary>
/// <param name="element">Elementet som innehåller eventet</param>
/// <param name="eventName">Namnet på eventet</param>
/// <param name="instance">Instansen som metoden ligger i</param>
/// <param name="method">Metoden som ska anropas</param>
/// <returns>void</returns>
Capitex.EventDelegateList.prototype.removeHandler = function(element, eventName, instance, method) {
    var index = this.indexOf(instance, method);
    if (index >= 0) {
        var item = this.items[index];
        $removeHandler(element, eventName, item.delegate);
        this.removeAt(index);
    }
}

Capitex.EventDelegateList.registerClass("Capitex.EventDelegateList");

/// <summary>Klass som representerar information om hur en metod ska anropas</summary>
/// <param name="instance">Instansen som metoden ligger i</param>
/// <param name="method">Metoden som ska anropas</param>
Capitex.DelegateItem = function(instance, method) {
    this.instance = instance;
    this.method = method;
    this.delegate = Type.createDelegate(this.instance, this.method);
}

Capitex.DelegateItem.registerClass("Capitex.DelegateItem");

Capitex.eventDelegates = new Capitex.EventDelegateList();

/// <summary>Klass som representerar information on hur en metod ska anropas</summary>
/// <param name="instance">Instansen som metoden ligger i</param>
/// <param name="method">Metoden som ska anropas</param>
Capitex.EventItem = function(instance, method) {
    this.instance = instance;
    this.method = method;
}

Capitex.EventItem.registerClass("Capitex.EventItem");

/*-----------------------------------------------------------------------------------------------*\
| Class _EventList
| En klass som representera en lista med events
| Avänds för att få rätt ordning på events framför allt för attachEvent metoden
|
| Parameters
| element       -   Elementet som innehåller eventet
| eventName     -   Namnet på eventet
\*-----------------------------------------------------------------------------------------------*/
Capitex._EventList = function(element, eventName) {
    this._items = [];
    Capitex.eventDelegates.addHandler(element, eventName, this, this.onFire);
}

/*-----------------------------------------------------------------------------------------------*\
| Sub add
| Lägger till en eventhanterare för eventet som denna instans hanterar
|
| Parameters
| instance      -   Instansen som metoden ligger i
| method        -   Metoden som ska anropas
\*-----------------------------------------------------------------------------------------------*/
Capitex._EventList.prototype.add = function(instance, method) {
    this._items.add(new Capitex.EventItem(instance, method));
}

/*-----------------------------------------------------------------------------------------------*\
| Sub remove
| Tar bort en eventhanterare för eventet som denna instans hanterar
|
| Parameters
| instance      -   Instansen som metoden ligger i
| method        -   Metoden som ska anropas
\*-----------------------------------------------------------------------------------------------*/
Capitex._EventList.prototype.remove = function(instance, method) {
    var item;
    for (var index = 0; index < this._items.length; index++) {
        item = this._items[index];
        if (item.method === method && item.instance === instance) {
            this._items.splice(index, 1);
            return true;
        }
    }
    return false;
}

Capitex._EventList.prototype.onFire = function() {
    var item;
    for (var index = 0; index < this._items.length; index++) {
        item = this._items[index];
        item.method.call(item.instance);
    }
}

Capitex._EventList.registerClass("Capitex._EventList");

Capitex.eventsLoad = new Capitex._EventList(window, "load");
Capitex.eventsResize = new Capitex._EventList(window, "resize");

Capitex._eventsApplicationLoadKeys = null;
Capitex._eventsApplicationLoad = null;

Capitex._fireApplicationLoadEvents = function(sender, args) {
    for (var i = 0; i < Capitex._eventsApplicationLoad.length; i++) {
        Capitex._eventsApplicationLoad[i]();
    }

    for (var item in Capitex._eventsApplicationLoadKeys) {
        Capitex._eventsApplicationLoadKeys[item]();
    }
}

/*-----------------------------------------------------------------------------------------------*\
| Sub $addLoadHandler
| Metod som lägger till en load hanterare
|
| Parameters:
| instance      -   Instansen av klassen som metoden ska köras i
| method        -   Metoden som ska köras
| key           -   Optional, nyckel som identifierar instansen. Detta är användbart då man vill 
|                   registrera en loadhandler som är garanterad att bara köras EN gång även om 
|                   man använder AJAX-panels mm.
\*-----------------------------------------------------------------------------------------------*/
$addLoadHandler = function(instance, method, key) {

    if (!Capitex._eventsApplicationLoad) {
        if ($isDefined(Sys.WebForms) && $isDefined(Sys.WebForms.PageRequestManager)) {
            Capitex._eventsApplicationLoad = [];
            Capitex._eventsApplicationLoadKeys = {}

            Capitex._addLoadHandler(instance, method, key);

            Sys.Application.add_load(Capitex._fireApplicationLoadEvents);
        }
        else {
            Capitex.eventsLoad.add(instance, method);
        }
    }
    else {
        Capitex._addLoadHandler(instance, method, key);
    }
}

Capitex._addLoadHandler = function(instance, method, key) {
    var handler = Type.createDelegate(instance, method);
    if (key)
        Capitex._eventsApplicationLoadKeys[key] = handler;
    else
        Capitex._eventsApplicationLoad.add(handler);
}

/*-----------------------------------------------------------------------------------------------*\
| Sub $removeLoadHandler
| Metod som tar bort en load hanterare
|
| Parameters:
| instance      -   Instansen av klassen som metoden ska köras i
| method        -   Metoden som ska köras
\*-----------------------------------------------------------------------------------------------*/
$removeLoadHandler = function(instance, method) {
    Capitex.eventsLoad.remove(instance, method);
}

/*-----------------------------------------------------------------------------------------------*\
| Sub $addLoadHandler
| Metod som lägger till en load hanterare
|
| Parameters:
| instance      -   Instansen av klassen som metoden ska köras i
| method        -   Metoden som ska köras
\*-----------------------------------------------------------------------------------------------*/
$addResizeHandler = function(instance, method) {
    Capitex.eventsResize.add(instance, method);
}

/*-----------------------------------------------------------------------------------------------*\
| Sub $removeLoadHandler
| Metod som tar bort en load hanterare
|
| Parameters:
| instance      -   Instansen av klassen som metoden ska köras i
| method        -   Metoden som ska köras
\*-----------------------------------------------------------------------------------------------*/
$removeResizeHandler = function(instance, method) {
    Capitex.eventsResize.add(instance, method);
}

/*-----------------------------------------------------------------------------------------------*\
| Sub $setTimeout
| Metod sätter upp en metod till att anropas vid specifika tillfällen
|
| Parameters:
| instance      -   Instansen av klassen som metoden ska köras i
| method        -   Metoden som ska köras
| 
| Returns:      -   Ett timeout id som kan användas för att ta bort timeouten
\*-----------------------------------------------------------------------------------------------*/
$setTimeout = function(instance, method, millisec, lang) {
    return setTimeout(Type.createDelegate(instance, method), millisec, lang);
}

$isDefined = function(obj) {
    return (typeof (obj) !== "undefined");
}

/*-----------------------------------------------------------------------------------------------*\
| Class TemplateParser
| Klass för att parsa mallar och ersätta viewpaths med information från objekt
|
| ViewPathen ska vara enligt följande modell:
| [Typnamn.fält]
| om fält är ett objekt så kan man även fortsätta viewpathen med att ange ett underfält:
| [Typnamn.fält.underfält]
| Alternativt så kan ett prefix specificeras för ett objekt, ViewPathen blir då följande
| [Prefix.fält.underfält]
\*-----------------------------------------------------------------------------------------------*/
Capitex.TemplateParser = function(template, keyStartChar, keyStopChar) {
    this._template = template;
    if (String.isNullOrEmpty(keyStartChar) || String.isNullOrEmpty(keyStopChar)) {
        this._regexKey = Capitex.TemplateParser.getKeyRegExp();
    }
    else {
        this._regexKey = new RegExp();
        this._regexKey.compile("\\" + keyStartChar + "([^\\" + keyStopChar + ":]+):?([^\\" + keyStopChar + "]+)?\\" + keyStopChar, "g");
    }
    this._objects = {};
}

Capitex.TemplateParser._keyPattern = "\\[([^\\]:]+):?([^\\]]+)?\\]";
Capitex.TemplateParser._keyRegExp = null;
Capitex.TemplateParser.getKeyRegExp = function() {
    if (Capitex.TemplateParser._keyRegExp === null) {
        Capitex.TemplateParser._keyRegExp = new RegExp();
        Capitex.TemplateParser._keyRegExp.compile(Capitex.TemplateParser._keyPattern, "g");
    }
    return Capitex.TemplateParser._keyRegExp;
}

/*-----------------------------------------------------------------------------------------------*\
| Sub addObject
| Metod som lägger till ett objekt som parsningen ska ta hänsyn till när en text parsas
|
| Parametrar:
| obj       -   objektet som ska finnas med vid parsningen
| prefix    -   om detta är null eller tomt, så blir prefixet typnamnet på objektet
\*-----------------------------------------------------------------------------------------------*/
Capitex.TemplateParser.prototype.addObject = function(obj, prefix) {
    if (String.isNullOrEmpty(prefix))
        prefix = obj.getName();

    this._objects[prefix] = obj;
}

/*-----------------------------------------------------------------------------------------------*\
| Sub parse
| Metod som parsar en mall
|
| Parametrar:
| template      -   mall som innehåller nyckelord som ska ersättas
\*-----------------------------------------------------------------------------------------------*/
Capitex.TemplateParser.prototype.parse = function(template) {
    if (String.isNullOrEmpty(template))
        template = this._template;
    if (String.isNullOrEmpty(template))
        throw Error.argumentNull("template");

    var regex = this._regexKey;
    var builder = new Sys.StringBuilder();
    var lastIndex = 0

    var result = regex.exec(template);
    while (result !== null && result.length > 0) {
        builder.append(template.substr(lastIndex, result.index - lastIndex));
        builder.append(this._getValue(result[1]));
        lastIndex = regex.lastIndex;
        result = regex.exec(template);
    }

    if (lastIndex < template.length - 1)
        builder.append(template.substr(lastIndex));

    return builder.toString();
}

Capitex.TemplateParser.prototype._getValue = function(viewPath) {
    var items = viewPath.split(".");
    var obj = this._objects[items[0]];

    for (var index = 1; index < items.length; index++)
        obj = obj[items[index]];

    return String(obj);
}

Capitex.TemplateParser.registerClass("Capitex.TemplateParser");

Type.registerNamespace("Capitex.UI")

Capitex.UI.isElementVisible = function(e) {
    if (e == document) 
        return true;

    if (!e) 
        return false;    
    if (!e.parentNode) 
        return false;    
    if (e.style) {        
        if (e.style.display == 'none') 
            return false;
        if (e.style.visibility == 'hidden') 
            return false;    
     }     
     //Try the computed style in a standard way    
     if (window.getComputedStyle) {
        var style = window.getComputedStyle(e, "");
        if (style.display == 'none') 
            return false;
        if (style.visibility == 'hidden') 
            return false;    
      }     
      //Or get the computed style using IE's silly proprietary way    
      var style = e.currentStyle;    
      if (style) {
          if (style['display'] == 'none')
              return false;
          if (style['visibility'] == 'hidden')
              return false;
      }

      return Capitex.UI.isElementVisible(e.parentNode);
}

$isElementVisible = Capitex.UI.isElementVisible;

Capitex.UI.depthFirstSearch = function(element, visitFunc) {
    if (visitFunc(element))
        return element;

    if (element.childNodes) {
        var ch = element.childNodes;
        for (var i = 0; i < ch.length; i++) {
            var r = Capitex.UI.depthFirstSearch(ch[i], visitFunc);
            if (r)
                return r
        }
    }
    return null;
}

$dfs = Capitex.UI.depthFirstSearch;

Capitex.UI.findElement = function(startElement, func, searchChildren) {
    var element = startElement;
    if (func(element)) {
        return element;
    }

    if (searchChildren) {
        if (element.childNodes != null) {
            for (var i = 0; i < element.childNodes.length; i++) {
                var result = Capitex.UI.findElement(element.childNodes[i], func, true)
                if (result != null)
                    return result;
            }
        }
    }
    else {
        if (element.parentElement != null) {
            return Capitex.UI.findElement(element.parentElement, func, false)
        }
    }
    return null;
}

Capitex.UI.findElementById = function(startElement, id, searchChildren) {
    return Capitex.UI.findElement(startElement, function(e) { return e.id == id; }, searchChildren)
}

Capitex.UI.findElementByTagName = function(startElement, tagName, searchChildren) {
    var tn = tagName.toLowerCase();
    return Capitex.UI.findElement(startElement, function(e) { return e.tagName.toLowerCase() == tn; }, searchChildren)
}

Capitex.UI.purgeElement = function(e) {
    var a = e.attributes, i, l, n;
    if (a) {
        l = a.length;
        for (i = 0; i < l; i += 1) {
            n = a[i].name;
            if (typeof e[n] === 'function') {
                e[n] = null;
            }
        }
    }
    a = e.childNodes;
    if (a) {
        l = a.length;
        for (i = 0; i < l; i += 1) {
            Capitex.UI.purgeElement(e.childNodes[i]);
        }
    }
}

Capitex.UI.setInnerHTML = function(e, html) {
    if (!e || typeof html !== 'string') {
        return null;
    }
    Capitex.UI.purgeElement(e);
    e.innerHTML = html;
}

$setInnerHTML = Capitex.UI.setInnerHTML;

/// <summary>Klass som registrerar och håller reda på eventhandlers för att enkelt kunna frigöra dem senare.</summary>
Capitex.UI.EventHandlerList = function() {
    this._handlers = [];
}
Capitex.UI.EventHandlerList.prototype = {

    addHandler: function(target, event, handler) {
        this._handlers.add({ "t": target, "e": event, "h": handler });
        $addHandler(target, event, handler);
    },

    clearHandlers: function() {
        for (var i = 0; i < this._handlers.length; i++) {
            var o = this._handlers[i];
            $removeHandler(o.t, o.e, o.h);
            o.t = null;
            o.e = null;
            o.h = null;
        }
    }
}

if(typeof(Sys)!=='undefined')Sys.Application.notifyScriptLoaded();