﻿var DivState = { "Waiting": 0, "Closed": 1, "Opening": 2, "Open": 3, "Closing": 4 };

function Calculator(mainDiv, varName) {

    this.mainDiv = mainDiv;
    this.varName = varName;
    this.divList = new Array();

    //this.transTime = 5000; // Transition time in ms
    this.Velocity = 30; // pixels/s
    this.Delay = 50; // ms
    this.OpenDelay = 100;
    this.OpenDelayTimeout = null;
    this.CloseDelay = 2000;
    this.HeadThresh = 50; // When to open/close price window
    this.CloseDelayTimeout = null;

    this.State = DivState.Closed;

    this.Debug = false;

    this.logDiv = null;

    this.AddToLog = function(T) {
        if (!this.Debug)
            return;
        this.logDiv.innerHTML += (T + '<br/>\r\n');
        this.logDiv.scrollTop = this.logDiv.scrollHeight;
    }

    this.HandleError = function(msg, url, linenumber) {
        this.AddToLog('ERROR LINE ' + linenumber + ': ' + msg);
    }

    if (this.Debug) {
        var dd = document.createElement('div');
        dd.style.position = 'absolute';
        dd.style.bottom = '0px';
        dd.style.right = '0px';
        dd.style.width = '400px';
        dd.style.height = '300px';
        dd.style.border = 'solid 1px #dddddd';
        dd.style.font = '15px arial,sans-serif';
        dd.style.overflow = 'scroll';

        document.body.appendChild(dd);

        this.logDiv = dd;

        this.AddToLog('DEBUGGING ENABLED');

        window.onerror = this.varName + '.HandleError';
    }

    this.AddDiv = function(DivID, ClosedHeight, OpenHeight) {
        var div = document.getElementById(DivID);
        this.divList.push(new CategoryDiv(div, ClosedHeight, OpenHeight));
    }

    this.SetHeight = function(I, H) {
        var cd = this.divList[I];
        cd.SetHeight(H);
    }

    this.WaitToOpen = function(I) {
        try {
            clearTimeout(this.OpenDelayTimeout);
            clearTimeout(this.CloseDelayTimeout);
        }
        catch (e) { }
        var action = this.varName + '.OpenDiv(' + I + ')';
        this.OpenDelayTimeout = setTimeout(action, this.OpenDelay);

        var cd = this.divList[I];
        cd.SetHeadHover();
    }

    this.WaitToCloseAll = function(I) {
        try {
            clearTimeout(this.OpenDelayTimeout);
            clearTimeout(this.CloseDelayTimeout);
        }
        catch (e) { }
        var action = this.varName + '.CloseAllBut()';
        this.CloseDelayTimeout = setTimeout(action, this.CloseDelay);

        var cd = this.divList[I];
        cd.ClearHeadHover();
    }

    this.OpenDiv = function(I) {
        if ((this.State == DivState.Closing) ||
            (this.State == DivState.Opening)) {
            this.AddToLog('OpenDiv() aborting becuase State=' + this.State);
            return;
        }

        this.AddToLog('OpenDiv(' + I + ')');
        var cd = this.divList[I];
        if (cd == null) {
            this.AddToLog('null for ' + I);
            return;
        }

        if (cd.State == DivState.Closing) {
            clearInterval(cd.IntervalID);
            this.AddToLog('Clear interval ' + cd.IntervalID);
        }
        if ((cd.State == DivState.Open) || (cd.State == DivState.Opening)) {
            this.AddToLog(I + ' Already open at OpenDiv()');
            return;
        }
        this.CloseAllBut(I);
        cd.ChangeState(DivState.Opening);
        this.State = DivState.Opening;
        var action = this.varName + '.OpenAction(' + I + ',' + cd.OpenHeight + ')';
        cd.IntervalID = setInterval(action, this.Delay);
        this.AddToLog('Create interval ' + cd.IntervalID + ' for action ' + action);
    }

    this.OpenAction = function(I, H) {
        var cd = this.divList[I];
        var currH = parseInt(cd.Div.style.height);
        this.AddToLog('OpenAction(' + I + ',' + H + ') currH=' + currH);
        var newH = Math.min(H, currH + this.Velocity);
        cd.SetHeight(newH);

        if (newH > this.HeadThresh)
            cd.SetHeadOpen();

        if (newH == H) {
            clearInterval(cd.IntervalID);
            this.AddToLog('Clear interval ' + cd.IntervalID);
            cd.ChangeState(DivState.Open);
            this.State = DivState.Open;
            this.AddToLog('Finished opening DIV ' + I + ' to height ' + H);
        }
    }

    this.CloseDiv = function(I) {

        this.AddToLog('CloseDiv(' + I + ')');
        var cd = this.divList[I];
        if (cd == null) {
            this.AddToLog('null for ' + I);
            return;
        }
        if (cd.State == DivState.Opening) {
            clearInterval(cd.IntervalID);
            this.AddToLog('Clear interval ' + cd.IntervalID);
        }
        if ((cd.State == DivState.Closed) || (cd.State == DivState.Closing)) {
            this.AddToLog(I + ' Already closed at CloseDiv()');
            return;
        }
        cd.ChangeState(DivState.Closing);
        this.State = DivState.Closing;
        var action = this.varName + '.CloseAction(' + I + ',' + cd.ClosedHeight + ')';
        cd.IntervalID = setInterval(action, this.Delay);
        this.AddToLog('Create interval ' + cd.IntervalID + ' for action ' + action);
    }

    this.CloseAction = function(I, H) {

        var cd = this.divList[I];
        var currH = parseInt(cd.Div.style.height);
        this.AddToLog('CloseAction(' + I + ',' + H + ') currH=' + currH);
        var newH = Math.max(H, currH - this.Velocity);
        cd.SetHeight(newH);

        if (newH < this.HeadThresh)
            cd.SetHeadClosed();

        if (newH == H) {
            clearInterval(cd.IntervalID);
            this.AddToLog('Clear interval ' + cd.IntervalID);
            cd.ChangeState(DivState.Closed);
            this.State = DivState.Closed;
            this.AddToLog('Finished closing DIV ' + I + ' to height ' + H);
        }
    }

    this.CloseAllBut = function(I) {
        this.AddToLog('CloseAllBut(' + I + ')');
        for (var i = 0; i < this.divList.length; i++)
            if (i != I)
            this.CloseDiv(i);
    }

    this.RemoveAllDimmers = function() {
        for (var i = 1; i < this.divList.length; i++)
            this.divList[i].RemoveDimmer();
    }
}

function CategoryDiv(Div, ClosedHeight, OpenHeight) {
    this.Div = Div;
    this.ClosedHeight = ClosedHeight;
    this.OpenHeight = OpenHeight;
    this.IntervalID = null;
    this.DimmerDiv = null;
    this.BaseHeaderDiv = null;
    this.DimActive = false;
    this.HeadIsOpen = null;

    this.SetHeight = function(H) {
        this.Div.style.height = parseInt(H) + 'px';
    }

    this.ChangeState = function(S) {
        this.State = S;

        if (this.DimActive) {
            if (S == DivState.Closed)
                this.AddDimmer(0.1);
            else
                this.RemoveDimmer();
        }
    }

    this.Subtotal = function() {
        var raw = this.Div.getElementsByTagName('div')[8].innerHTML;
        return parseFloat(raw.match(/\d+/));
    }
    

    this.SetHeadOpen = function() {
        if (this.HeadIsOpen)
            return;
        this.HeadIsOpen = true;
        var hd = this.GetHeaderDiv();
        hd.className = hd.className.replace(' closed', '');
    }

    this.SetHeadClosed = function() {
        if (!this.HeadIsOpen)
            return;
        this.HeadIsOpen = false;
        var hd = this.GetHeaderDiv();
        if (hd.className.indexOf(' closed') < 0) {
            if (this.Subtotal() > 0)
                hd.className = hd.className + ' closed';
        }
    }

    this.SetHeadHover = function() {
        var hd = this.GetHeaderDiv();
        if (hd.className.indexOf(' hover') < 0)
            hd.className = hd.className + ' hover';
    }

    this.ClearHeadHover = function() {
        var hd = this.GetHeaderDiv();
        if (hd.className.indexOf(' hover') >= 0)
            hd.className = hd.className.replace(' hover','');
    }

    this.GetHeaderDiv = function() {
        var childDivs = this.Div.getElementsByTagName('DIV');
        for (var i = 0; i < childDivs.length; i++) {
            if (childDivs[i].className.indexOf('head') >= 0)
                return childDivs[i];
        }
        return null;
    }

    this.RemoveDimmer = function() {
        try { this.Div.removeChild(this.DimmerDiv); }
        catch (e) { }
    }

    this.SetDimmerOpacity = function(O) {
        try { this.DimmerDiv.style.opacity = O; }
        catch (e) { }
    }

    this.AddDimmer = function(O) {
        this.DimmerDiv = document.createElement('div');
        this.DimmerDiv.style.width = '100%';
        this.DimmerDiv.style.height = this.ClosedHeight + 'px';
        this.DimmerDiv.style.zIndex = '10000';
        this.DimmerDiv.style.backgroundColor = '#000000';
        this.SetDimmerOpacity('0.05');
        this.DimmerDiv.style.position = 'absolute';
        this.DimmerDiv.style.left = '0px';
        this.DimmerDiv.style.top = '0px';

        try {
            this.Div.appendChild(this.DimmerDiv);
        }
        catch (e) { }
    }

    this.ChangeState(DivState.Closed);
}


