﻿TabGridContainer = function(dropElement, scale)
{
    this.HiddenDataItemSeparator = ':';
    this.HiddenDataTripletSeparator = '|';
    this.HiddenDataChordListSeparator = '|';
    this.HiddenDataChordListItemSeparator = '-';
    
    this.Browser = this.GetBrowser();
    
    this.OwnerPrefix = dropElement.getAttribute('OwnerPrefix');
    this.DropElement = dropElement;
    
    // call the SetNewElementName function
    if (this.OwnerPrefix == 'GLOBAL')
    {
        eval("SetNewElementName_" + ModifierListOwnerPrefix + "()");
        this.OwnerPrefix = ModifierListOwnerPrefix;
    }
    else
    {
        eval("SetNewElementName_" + this.OwnerPrefix + "()");
    }
    
    this.Width = ParseNumber(GetElementWidth(dropElement));
    this.Height = ParseNumber(GetElementHeight(dropElement));

    this.ItemObject = this.GetItemObject();
        
    
    // dropped item properties
    this.GetPosCenterTop(); 
    this.GetPosCenterLeft();
    
    // ImageDataItem represents 1-24 in the case of dropped numbers, b12 in the case of a half bend etc
    this.ImageDataItem = dropElement.getAttribute('ImgNumber');

    // sort out scaling
    if (isNaN(scale)) 
    {
        scale = GetGridScale(this.OwnerPrefix);        
    }
    this.StaffLength = 660;    
    //20;
    this.FretHeight = this.StaffLength / (parseInt(scale) + 1); 
    
    this.StringSeparation = 10;
    

    this.IsWholeChord = dropElement.id.indexOf('divGeneratedDropChord') != -1;
    this.IsDivider = this.ImageDataItem == 30;
    this.IsModifier = dropElement.getAttribute('ModifierList') != null;
    
    this.DividerToolBoxTop = "0px";
    this.DividerToolBoxLeft = "670px";
    
    
    this.HiddenField = document.getElementById(this.OwnerPrefix + 'hiddenData');
    
    
}


TabGridContainer.prototype =
{
    GetItemObject: function ()
    {
        switch (this.DropElement.getAttribute('SpecialPositionType'))
        {
            case "Bend":
                Log('GetItemObject->Bend');
                return new Bend(this.DropElement);

            case "HammerPull":
                Log('GetItemObject->HammerPull');
                return new HammerPull(this.DropElement);

            case "SlideUp":
            case "SlideDown":
                return new Slide(this.DropElement);

            case "FreeModifier":
                return new FreeModifier(this.DropElement);

            default:
                Log('GetItemObject->Item');
                return new Item(this.DropElement);
        }
    },


    GetBrowser: function ()
    {
        if (navigator.userAgent.indexOf('MSIE') != -1)
        {
            return 'IE';
        }
        if (navigator.userAgent.indexOf('Chrome') != -1)
        {
            return 'CHROME';
        }
        if (navigator.userAgent.indexOf('Firefox') != -1)
        {
            return 'FIREFOX';
        }
        if (navigator.userAgent.indexOf('Netscape') != -1)
        {
            return 'FIREFOX';
        }
    },



    GetPosCenterTop: function ()
    {
        this.PosCenterTop = this.ItemObject.GetPosCenterTop();
    },

    GetPosCenterLeft: function ()
    {
        this.PosCenterLeft = this.ItemObject.GetPosCenterLeft();
    },



    IsOver: function ()
    {
        Log('IsOver');

        var string6Top = this.StringSeparation * 5;
        var lastFretLeft = this.StaffLength;

        var upperLimit = 0 - (this.StringSeparation / 2);
        if (this.ItemObject.GetIsOverUpperLimit)
        {
            // if the upper limit is overridden we'll use it
            upperLimit = this.ItemObject.GetIsOverUpperLimit();
        }

        var lowerLimit = string6Top + (this.StringSeparation / 2);



        var withinVerticalBounds = (this.PosCenterTop > upperLimit) && (this.PosCenterTop < lowerLimit);
        var withinHorizontalBounds = (this.PosCenterLeft > (0 - (this.FretHeight / 2))) && (this.PosCenterLeft < lastFretLeft + (this.FretHeight / 2));

        if (withinVerticalBounds && withinHorizontalBounds)
        {
            Log('IsOver->TRUE');
            return true;
        }

        Log('IsOver->WithinVerticalBounds->' + withinVerticalBounds);
        Log('IsOver->WithinHorizontalBounds->' + withinHorizontalBounds);
        Log('IsOver->FALSE');

        return false;
    },



    IsNotOver: function ()
    {
        // we must see if the item being thrown away is in the hidden data - if it is it must be removed
        // remove the item from the hidden string if it is present
        this.RemoveData(this.DropElement.getAttribute('ImgData'), this.DropElement.getAttribute('HorizontalPosition'), this.DropElement.getAttribute('VerticalPosition'));
        return false;
    },





    MoveItem: function ()
    {
        Log('MoveItem');

        var verticalPosition = this.FindVerticalPosition();
        var horizontalPosition = this.FindHorizontalPosition();

        if (this.IsWholeChord)
        {
            // we're moving a whole chord
            this.MoveWholeChord(horizontalPosition);
        }
        else
        {
            this.MoveSingleItem(this.ImageDataItem, horizontalPosition, verticalPosition);
        }
    },




    MoveSingleItem: function (imageDataItem, horizontalPosition, verticalPosition)
    {
        Log('MoveSingleItem');
        Log('MoveSingleItem->imageDataItem:' + imageDataItem + ', hpos:' + horizontalPosition + ', vpos:' + verticalPosition);

        if (this.DropElement.id != '' && this.DropElement.id.indexOf('_tbi') == -1)
        {
            // IMPORTANT
            // i am using dropElement.HorizontalPosition etc as a way of getting data from the OLD positioned item
            // rather than the new HorizontalCoOrdinate value passed in for the case of RE-POSITIONING elements already dropped
            this.RemoveData(this.DropElement.getAttribute('ImgData'), this.DropElement.getAttribute('HorizontalPosition'), this.DropElement.getAttribute('VerticalPosition'));
        }

        if (!this.CurrentDataCanRemain(horizontalPosition, verticalPosition))
        {
            // we may have dropped an item over another item already on the grid
            // we may have an item visible which now has no data for it in the hidden string so needs to be made invisible
            this.HideItemByPosition(horizontalPosition, verticalPosition);

            // we need to do the above first or we will hide the image we are dropping:
            this.RemoveDataByPosition(horizontalPosition, verticalPosition);
        }

        var newItem = this.GetNewItem(imageDataItem, horizontalPosition, verticalPosition);

        this.SetPosition(newItem);
        this.SetData(imageDataItem, horizontalPosition, verticalPosition);
    },


    // some data items can occupy the same space as others (ie, a number and a bend)
    CurrentDataCanRemain: function (horizontalPosition, verticalPosition)
    {
        var dataItem = this.GetDataItemByPosition(horizontalPosition, verticalPosition);

        Log('CurrentDataCanRemain');
        Log('CurentDataCanRemain->CurrentDataItem->' + dataItem);

        if (!dataItem)
        {
            // no current data so nothing to worry about
            return true;
        }
        else
        {
            return this.ItemObject.CurrentDataCanRemain(dataItem);
        }
    },



    MoveWholeChord: function (horizontalPosition)
    {
        Log('MoveWholeChord');

        // we need to get the horizontal co-ordinate 
        // then get the chord data (which is the value of the list

        var list = document.getElementById(this.DropElement.getAttribute('ListOwnerId'));
        var chordData = list.options[list.selectedIndex].value;

        Log('MoveWholeChord->ChordData: ' + chordData);

        var arrayChordElements = chordData.split(this.HiddenDataChordListSeparator);

        // we need to apply the horizontal value passed in to each of the chord elements as they dont have this yet
        var chordElementCounter;
        for (chordElementCounter = 0; chordElementCounter < arrayChordElements.length; chordElementCounter++)
        {
            // data elements are in the form stringNumber-fretNumber
            // or, VerticalCoOrdinate-ImageNumber
            var arrayVertAndFret = arrayChordElements[chordElementCounter].split(this.HiddenDataChordListItemSeparator);
            var verticalPosition = arrayVertAndFret[0];
            var imageDataItem = arrayVertAndFret[1];

            // IMPORTANT: dropped items are zero based the whole chord items are based at 1
            verticalPosition = verticalPosition - 1;

            this.ItemObject.IsWholeChordItem = true;
            this.MoveSingleItem(imageDataItem, horizontalPosition, verticalPosition);
        }
    },



    FindHorizontalPosition: function ()
    {
        Log('FindHorizontalPosition')

        var counter = 0;
        while (true)
        {
            if (counter > 500)
            {
                Log('FindHorizontalPosition->Unable to find position');
                alert('Unable to find horizontal position');
                return;
            }

            var rangeLeft = (counter * this.FretHeight) - (this.FretHeight / 2);
            var rangeRight = (counter * this.FretHeight) + (this.FretHeight / 2);

            //Log('FindHorizontalPosition->RangeLeft->' + rangeLeft);
            //Log('FindHorizontalPosition->RangeRight->' + rangeRight);

            if ((this.PosCenterLeft >= rangeLeft) && (this.PosCenterLeft <= rangeRight))
            {
                break;
            }
            counter += this.ItemObject.HorizontalSeparationIncrement;
        }

        Log('FindHorizontalPosition->' + counter);
        return counter;
    },



    FindVerticalPosition: function ()
    {
        Log('FindVerticalPosition');

        var counter = 0;
        if (this.ItemObject.FindVerticalPositionCounterStart)
        {
            // this can be overridden in the specific object
            counter = this.ItemObject.FindVerticalPositionCounterStart();
        }

        while (true)
        {
            if (counter > 50)
            {
                // safety break to prevent infinite looping:
                Log('FindVerticalPosition->Unable to find position');
                alert('Unable to find vertical position');
                return;
            }

            var rangeTop = (counter * this.StringSeparation) - (this.StringSeparation / 2);
            var rangeBottom = (counter * this.StringSeparation) + (this.StringSeparation / 2);

            //Log('FindVerticalPosition->RangeTop->' + rangeTop);
            //Log('FindVerticalPosition->RangeBottom->' + rangeBottom);

            if ((this.PosCenterTop >= rangeTop) && (this.PosCenterTop <= rangeBottom))
            {
                break;
            }
            counter++;
        }

        Log('FindVerticalPosition->' + counter);
        return counter;
    },







    SetPosition: function (divElement)
    {
        Log('SetPosition');

        var verticalPosition = divElement.getAttribute('VerticalPosition');
        var horizontalPosition = divElement.getAttribute('HorizontalPosition');

        Log('SetPosition->VerticalPosition->' + verticalPosition);
        Log('SetPosition->HorizontalPosition->' + horizontalPosition);

        var height = GetElementHeight(divElement);
        var width = GetElementWidth(divElement);

        var top = this.ItemObject.GetActualTop(verticalPosition, this.StringSeparation);
        var left = this.ItemObject.GetActualLeft(horizontalPosition, this.FretHeight);

        //        Log('SetPosition->ItemHeight->' + height);
        //        Log('SetPosition->ItemWidth->' + width);
        Log('SetPosition->Top->' + top);
        Log('SetPosition->Left->' + left);

        if (this.IsDivider)
        {
            // special positioning here
            // we want to position this element in the vertical center of the grid (its a divider)
            top = 0;
        }

        divElement.style.top = top + 'px';
        divElement.style.left = left + 'px';

        if (left > 670 && !this.IsDivider)
        {
            // we may have scaled the image off the end of the grid!
            divElement.style.visibility = "hidden";
        }
        else
        {
            divElement.style.visibility = "visible";
        }
    },



    // add a new Name-HorizontalPosition-VerticalPosition item to the hidden data field
    SetData: function (imageDataItem, horizontalPosition, verticalPosition)
    {
        Log('SetData');

        var currentData = this.HiddenField.value;

        if (currentData.length > 0) // we need to put a separator bar in place
        {
            currentData += this.HiddenDataTripletSeparator;
        }

        // sometimes the generated item has its dataitem dependant on the string, length etc so is not availabe in the DropElement   
        if (this.ItemObject.DataItemRequiresRefresh)
        {
            imageDataItem = this.ItemObject._DataItem;
        }

        var itemData = imageDataItem + this.HiddenDataItemSeparator + verticalPosition + this.HiddenDataItemSeparator + horizontalPosition;
        currentData += itemData;

        Log('SetData->' + itemData);
        this.HiddenField.value = currentData;
    },



    // removes a Name-HorizontalPosition-VerticalPosition item from the hidden data field
    RemoveData: function (imageName, horizontalPosition, verticalPosition)
    {
        Log('RemoveData');

        var searchString = imageName + this.HiddenDataItemSeparator + verticalPosition + this.HiddenDataItemSeparator + horizontalPosition;
        var hiddenDataValue = this.HiddenField.value;

        Log('RemoveData->SearchString->' + imageName + ',' + verticalPosition + ',' + horizontalPosition + ', ' + searchString);

        if (hiddenDataValue.indexOf(searchString) != -1)
        {
            hiddenDataValue = StringRemove(hiddenDataValue, searchString);
            hiddenDataValue = CleanUpData(hiddenDataValue);
            this.HiddenField.value = hiddenDataValue;
        }
    },


    // removes a Name-HorizontalPosition-VerticalPosition item by building the full N-H-V item 
    // then calling RemoveData with the whole item passed in
    RemoveDataByPosition: function (horizontalPosition, verticalPosition)
    {
        Log('RemoveDataByPosition');

        // if the item exists in the hidden data

        var dataItem = this.GetDataItemByPosition(horizontalPosition, verticalPosition);

        if (dataItem)
        {
            Log('RemoveDataByPosition->Removing data');
            // re-use this function to remove the entire item from the hidden string
            this.RemoveData(dataItem, horizontalPosition, verticalPosition);
        }
    },


    // returns just the data item (ie, 24, b1_12) from a particular position
    GetDataItemByPosition: function (horizontalPosition, verticalPosition)
    {
        var searchString = this.HiddenDataItemSeparator + verticalPosition + this.HiddenDataItemSeparator + horizontalPosition;
        var hiddenDataValue = this.HiddenField.value;

        Log('GetDataItemByPosition->SearchString->' + searchString);

        // if the item exists in the hidden data
        if (hiddenDataValue.indexOf(searchString) != -1)
        {
            // build the full search string with the ImgNumber too then re-use RemoveItemFromHiddenString
            var dataItem;

            // this could be 1-2-3|12 or just 12 etc
            var strStart = hiddenDataValue.substr(0, hiddenDataValue.indexOf(searchString));

            if (strStart.indexOf(this.HiddenDataTripletSeparator) != -1)
            {
                // we can just get the remainder of the string after the last '|'
                dataItem = strStart.substr(strStart.lastIndexOf(this.HiddenDataTripletSeparator) + 1);
            }
            else
            {
                // if the above condition is not met then strStart already contains just the number
                dataItem = strStart;
            }

            return dataItem;
        }

        return null;
    },



    // if an item is found at (Horizontal,Vertical) then it is hidden
    HideItemByPosition: function (horizontalPosition, verticalPosition)
    {
        Log('HideItemByPosition');
        Log('HideItemByPosition->hpos:' + horizontalPosition + ', vpos:' + verticalPosition);

        for (i = 0; i < document.images.length; i++)
        {
            if (document.images[i].getAttribute('OwnerPrefix'))
            {
                if (/*document.images[i].getAttribute('OwnerPrefix') == this.OwnerPrefix && */document.images[i].getAttribute('HorizontalPosition') == horizontalPosition && document.images[i].getAttribute('VerticalPosition') == verticalPosition)
                {
                    document.images[i].style.visibility = 'hidden';
                }
            }
        }
    },




    GetNewItem: function (droppedImageData, horizontalPosition, verticalPosition)
    {
        Log('GetNewItem');

        // NewItemCounterTabGrid is a global variable
        var newImageId = 'newImg' + NewItemCounterTabGrid;

        // newElementName is set in the container via a function SetNewElementName_OWNER_PREFIX() set by the tabgrid
        var newSpanElement = document.getElementById(newElementName);

        var imageSourceName = this.DropElement.getAttribute('ImageSrcName');
        // just in case this isnt present (in the case of a dropped whole chord)
        if (!imageSourceName)
        {
            imageSourceName = droppedImageData;
        }


        /////////////////////////////////////////////////////////////////////////////////////////
        // THESE PROPERTIES MUST MATCH THOSE GENERATED IN THE SERVER CONTROL FOR THE IMG ITEMS //
        /////////////////////////////////////////////////////////////////////////////////////////

        if (this.Browser == 'FIREFOX')
        {
            newSpanElement.parentNode.innerHTML = newSpanElement.parentNode.innerHTML + this.ItemObject.GetImage(droppedImageData, horizontalPosition, verticalPosition, newImageId, imageSourceName);
        }
        else
        {
            newSpanElement.outerHTML = "<span id='" + newElementName + "'></span>" + this.ItemObject.GetImage(droppedImageData, horizontalPosition, verticalPosition, newImageId, imageSourceName);
        }

        NewItemCounterTabGrid++;

        return document.getElementById(newImageId);
    },



    ResetItem: function ()
    {
        Log('ResetItem');

        if (this.Browser == 'FIREFOX')
        {
            // FireFox has lost the plot and needs to be re-told everything......
            // (it cant handle it when script is in multiple files...)

            this.ItemObject.ResetItem();

            var top = this.DropElement.style.top;
            var left = this.DropElement.style.left;

            this.DropElement = document.getElementById(this.DropElement.id);
            this.DropElement.style.top = top;
            this.DropElement.style.left = left;

            if (this.DropElement.id.indexOf('_img') != -1 || this.DropElement.id.indexOf('newImg') != -1)
            {
                this.DropElement.style.visibility = 'hidden';
            }
        }
        else
        {
            this.ItemObject.ResetItem();
        }
    }


}
