var panelSystemComputerFactory = {};

function internalMakeOccupationMapKey(x, y)
{
    return "f_" + x.toString() + "_" + y.toString();
}

panelSystemComputerFactory.create = function()
{
    var rResult = {};

    rResult.inputData = {};

    rResult.staticData = {};
    rResult.staticData.segments = [];

    rResult.dynamicData = {};

    rResult.dynamicData.capacityData = {};

    rResult.dynamicData.volatileData = {};
    rResult.dynamicData.volatileData.segments = [];

    rResult.dynamicData.billData = {};

    rResult.awake = function(solarPotential)
    {
        this.inputData.panels = solarPotential.Panels;
        this.inputData.panelPortraitSize = solarPotential.PanelPortraitSize;

        this.staticData.panelCount = this.inputData.panels.length;
        this.staticData.totalEnergy = 0.0;
        this.staticData.maximumSegmentIndex = -1;
        for (var i = 0 ; i < this.inputData.panels.length; i++)
        {
            this.staticData.totalEnergy += this.inputData.panels[i].Energy;
            this.staticData.maximumSegmentIndex = Math.max(this.inputData.panels[i].SegmentIndex, this.staticData.maximumSegmentIndex);
        }

        rResult.staticData.segments = new Array(this.staticData.maximumSegmentIndex + 1);
        for (var i = 0; i < rResult.staticData.segments.length; i++)
        {
            rResult.staticData.segments[i] = {};
            rResult.staticData.segments[i].occupationMap = {};
        }

        var nullOccupationValue = this.inputData.panels.length + 1000;
        for (var i = 0 ; i < this.inputData.panels.length; i++)
        {
            var panel = this.inputData.panels[i];
            var occupationMap = rResult.staticData.segments[panel.SegmentIndex].occupationMap;
            var occupationMapKey = internalMakeOccupationMapKey(panel.LayoutIndex.X + 1, panel.LayoutIndex.Y);
            occupationMap[occupationMapKey] = nullOccupationValue;
            var occupationMapKey = internalMakeOccupationMapKey(panel.LayoutIndex.X - 1, panel.LayoutIndex.Y);
            occupationMap[occupationMapKey] = nullOccupationValue;
            var occupationMapKey = internalMakeOccupationMapKey(panel.LayoutIndex.X, panel.LayoutIndex.Y + 1);
            occupationMap[occupationMapKey] = nullOccupationValue;
            var occupationMapKey = internalMakeOccupationMapKey(panel.LayoutIndex.X, panel.LayoutIndex.Y - 1);
            occupationMap[occupationMapKey] = nullOccupationValue;
        }

        for (var i = 0 ; i < this.inputData.panels.length; i++)
        {
            var panel = this.inputData.panels[i];
            var occupationMap = rResult.staticData.segments[panel.SegmentIndex].occupationMap;
            var occupationMapKey = internalMakeOccupationMapKey(panel.LayoutIndex.X, panel.LayoutIndex.Y);
            occupationMap[occupationMapKey] = i;
        }
    }

    rResult.calculatePanelLayoutCircumferenceInInches = function(requestInput)
    {
        var rResult = this.calculatePanelLayoutCircumference(requestInput); 
        rResult.length = rResult.length * 39.3701;
        return rResult;
    }
 
    rResult.calculatePanelLayoutCircumference = function(requestInput)
    {
        var panelCount = Math.min(requestInput.panelCount, this.inputData.panels.length);
        var rResultCircumference = {};
        rResultCircumference.length = 0;
        rResultCircumference.segments = new Array(this.staticData.segments.length);
        for (var i = 0; i < rResultCircumference.segments.length; i++)
        {
            rResultCircumference.segments[i] = {};
            rResultCircumference.segments[i].length = 0;
        }

        var neighbours = 
        [
            {
                dx : 1,
                dy : 0,
                dlcx : 1,
                dlcy : 0
            },
            {
                dx : -1,
                dy : 0,
                dlcx : 1,
                dlcy : 0
            },
            {
                dx : 0,
                dy : 1,
                dlcx : 0,
                dlcy : 1
            },
            {
                dx : 0,
                dy : -1,
                dlcx : 0,
                dlcy : 1
            }
        ];

        for (var i = 0 ; i < panelCount; i++)
        {
            var panelWidth;
            var panelHeight;
            var panel = this.inputData.panels[i]; 
            if (panel.Orientation == 0)
            {
                panelHeight = this.inputData.panelPortraitSize.Width;
                panelWidth = this.inputData.panelPortraitSize.Height;
            }
            else
            {
                panelWidth = this.inputData.panelPortraitSize.Width;
                panelHeight = this.inputData.panelPortraitSize.Height;
            }
            
            var occupationMap = this.staticData.segments[panel.SegmentIndex].occupationMap;

            for (var n = 0; n < neighbours.length; n++)
            {
                var occumationMapValue = occupationMap[internalMakeOccupationMapKey(panel.LayoutIndex.X + neighbours[n].dx, panel.LayoutIndex.Y + neighbours[n].dy)];
                if (occumationMapValue < panelCount)
                {
                }
                else
                {
                    var dl = panelWidth *  neighbours[n].dlcx + panelHeight *  neighbours[n].dlcy;
                    rResultCircumference.segments[panel.SegmentIndex].length += dl;
                    rResultCircumference.length += dl;
                }
            }
        }
        return rResultCircumference;
    }

    rResult.calculatePanelCountForBill = function(request)
	{
		var neededkWh = request.electricalBillValue / request.electricalCostPerkWh;
		var calculatedkWh = 0.0;
		var panelCount = 0;

		for(;(panelCount < this.inputData.panels.length) && (calculatedkWh < neededkWh); panelCount++)
		{
			calculatedkWh += ((request.wattage / 1000.0) * this.inputData.panels[panelCount].Energy * request.energyMultiplier) / 12.0;
		}

        return panelCount;
	}
    
    rResult.updateDynamicBillData = function(requestInput)
    {
        this.dynamicData.billData.panelCount = this.calculatePanelCountForBill(requestInput);
        return this.dynamicData.billData;
    }


    rResult.updateDynamicCapacityData = function(requestInput)
    {
        this.dynamicData.capacityData.totalEnergy = (requestInput.wattage / 1000.0) * this.staticData.totalEnergy * requestInput.energyMultiplier;
        this.dynamicData.capacityData.maxYearlyProduction = parseInt(this.dynamicData.capacityData.totalEnergy, 10);
        this.dynamicData.capacityData.maxSystemCapacity = this.inputData.panels.length * requestInput.wattage;
        return this.dynamicData.capacityData;
    }

    rResult.updateDynamicVolatileData = function(requestInput)
    {
        this.dynamicData.volatileData.panelCount = requestInput.panelCount;

		this.dynamicData.volatileData.totalEnergy = 0.0;
		for (var i = 0; i < this.dynamicData.volatileData.panelCount; i++)
		{
			this.dynamicData.volatileData.totalEnergy += (requestInput.wattage / 1000.0) * this.inputData.panels[i].Energy * requestInput.energyMultiplier;
		}
		
        this.dynamicData.volatileData.systemCapacity = (requestInput.wattage) * this.dynamicData.volatileData.panelCount;
		this.dynamicData.volatileData.electricalBillWithCurrentPanels = parseInt((this.dynamicData.volatileData.totalEnergy / 12) * requestInput.electricalCostPerkWh, 10);
        return this.dynamicData.volatileData;
    }

    return rResult;

}

if (typeof module !== 'undefined')
{
    module.exports = panelSystemComputerFactory;
}
