﻿
ChordBoxContainer = function(dropElement)
{
    this.Browser = this.GetBrowser();

    this.OwnerPrefix = dropElement.getAttribute('OwnerPrefix');
    this.DropElement = dropElement;
    
    // chord box properties
    this.StringSeparationEdit = 20;
    this.StringSeparationView = 10;
    this.FretHeightEdit = 25;
    this.FretHeightView = 10;
    this.AestheticDotCompensateEdit = 10;
    this.AestheticDotCompensateView = 3;
    
    // dropped item properties
    this.CenterTop = ParseNumber(dropElement.style.top) + (ParseNumber(dropElement.offsetHeight) / 2);
    this.CenterLeft = ParseNumber(dropElement.style.left) + (ParseNumber(dropElement.offsetWidth) / 2);
    this.Width = ParseNumber(dropElement.offsetWidth);
    this.Height = ParseNumber(dropElement.offsetHeight);
    this.IsDot = (dropElement.id.indexOf('imgDragDot') != -1 || dropElement.id.indexOf('Dot_String') != -1)
    this.IsNumber = ((dropElement.id.indexOf('Number_String') != -1) || (dropElement.id.indexOf('ToolBarNumber') != -1));
    
    // tool bar item constants
    this.ImgDragDotTop = "30px";
    this.ImgDragDotLeft = "-33px";
    this.ToolBarNumberLeft = "-29px";
    this.ToolBarNumberSeparation = 15;
    
    this.NewItemHtml = '';
    
    // dropped number constants (taking in to account sizing and scaling)
    this.NumberTopEdit = "110px";
    this.NumberTopView = "49px";
    this.SpecialNumberTopEdit = "-12px";
    this.SpecialNumberTopView = "-12px";
    
    
    this.HiddenField = document.getElementById(this.OwnerPrefix + 'hiddenData');
}


ChordBoxContainer.prototype = 
{
    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';
    },
    

    IsOver : function()
    {
        var fret4Top = this.FretHeightEdit * 4;
        var string6Left = this.StringSeparationEdit * 5;
        
        var withinVerticalBounds = this.CenterTop > (0 - (this.FretHeightEdit/2)) && this.CenterTop < fret4Top + (this.FretHeightEdit/2);
        var withinHorizontalBounds = this.CenterLeft > (0 - (this.StringSeparationEdit/2)) && this.CenterLeft < (string6Left + (this.StringSeparationEdit/2));

        if (withinVerticalBounds && withinHorizontalBounds)
        {
            return true;
        }
        return false;
    },
    
    
    
    MoveItem : function()
    {
        Log('MoveItem->');
        
        // find out which string and fret the dot has been dropped on and move the dot for that
        // string to that position, and move imgDragDot back to its original position
        // loop through the strings to find which one it has been dropped on to
        
        var intStringNumber = this.FindString();
        var intFretNumber = this.FindFret();
        
        if (intStringNumber == -1) { alert('Cant find string'); return; }
        if (intFretNumber == -1) { alert('Cant find fret'); return }

        if (this.IsDot)
        {
            Log('MoveItem->IsDot->true');            
            
            var dotElement = document.getElementById(this.OwnerPrefix + 'Dot_String' + intStringNumber);
            dotElement.setAttribute('String', intStringNumber);
            dotElement.setAttribute('Fret', intFretNumber);
            dotElement.style.visibility = 'visible';
            
            // we do not want to use small sizing here as its deffinately in edit mode
            this.SetPositionDot(dotElement, false); 
            this.SetDataDot(intFretNumber, intStringNumber);
            
            // if we have moved an existing dot we need to make it invisible (rather than imgDragDot)
            // and also remove the old dots data from the hidden field
            if (this.DropElement.id.indexOf('Dot_String') != -1)
            {
                this.RemoveDataDot(this.DropElement.getAttribute('String'));

                // dont hide the dot if its being repositioned ON THE SAME STRING!!!
                if (this.DropElement.getAttribute('String') != intStringNumber)
                {
                    document.getElementById(this.DropElement.id).style.visibility = 'hidden';
                }
            }
        }
        else if (this.IsNumber)
        {
            Log('MoveItem->IsNumber->true');

            // we only care about the string number, not fret as the numbers are all placed at the bottom in the same level

            // intNumber can be 1-4 or O or X
            var intNumber = this.DropElement.getAttribute('Number');

            var numberElement = this.GetNewImage(intNumber, 0, intStringNumber);
            numberElement.setAttribute('String', intStringNumber);
            numberElement.setAttribute('Fret', 0);

            this.RemoveDataNumber(this.DropElement.getAttribute('String'), intNumber);
            this.RemoveDataNumber(intStringNumber, intNumber);
            this.HideNumberByPosition(intStringNumber, intNumber);
            
            // we want to use large sizing as its in edit mode
            this.SetPositionNumber(numberElement, false);    
            this.SetDataNumber(intStringNumber, intNumber);

            if (this.DropElement.id.indexOf('Number_String') != -1)
            {
                // we have re-moved an already positioned number so we can simply hide it now:
                this.DropElement.style.visibility = 'hidden';
            }
        }
        else
        {
            alert('Cant handle dropped item type');
        }

        return;
    },
    
    
    
    IsNotOver : function()
    {
        Log('IsNotOver->');
        
        if (this.DropElement.id == "imgDragDot" || this.DropElement.id.indexOf('ToolBarNumber') != -1)
        {
            // do nothing as its not a problem - it does not affect whats on the chord box already
            return;
        }
        else if (this.DropElement.id.indexOf('Number_String') != -1)
        {            
            // thrown a number away
            this.RemoveDataNumber(this.DropElement.getAttribute('String'), this.DropElement.getAttribute('Number'));
            this.HideNumberByPosition(this.DropElement.getAttribute('String'), this.DropElement.getAttribute('Number'));
            this.DropElement.style.visibility = 'hidden';
        }
        else
        {
            // thrown a dot away
            this.RemoveDataDot(this.DropElement.getAttribute('String'));
            this.DropElement.style.visibility = 'hidden';
        }
    },
    
    
    
    ResetItem : function()
    {
        Log('ResetItem->');
        
        if (this.DropElement.id == this.OwnerPrefix + "imgDragDot") 
        {
            // its imgDragDot
            // put imgDragDot back to its original position
            var dot = eval("document.forms[0]." + this.OwnerPrefix + "imgDragDot");
            dot.style.top = this.ImgDragDotTop;
            dot.style.left = this.ImgDragDotLeft;
            dot.style.zIndex = "50";
            dot.style.visibility = "visible";
        }
        else if (this.DropElement.id.indexOf('Dot_String') != -1) 
        {
            // its a dot on a string
            // put the dot back in its start position
            var dotCounter
            for (dotCounter = 1; dotCounter < 7; dotCounter ++)
            {
                var dotNameCompare
                dotNameCompare = this.OwnerPrefix + "Dot_String" + dotCounter
                if (this.DropElement.id == dotNameCompare)
                {
                    dotToBeMoved = eval("document.forms[0]." + this.DropElement.id + ".style")

                    // dont hide the dot if its been moved back ON TO THE SAME STRING!!!!!!
                    if (this.DropElement.getAttribute('String') != dotCounter)
                    {
                        dotToBeMoved.visibility = "hidden"
                        dotToBeMoved.top = 0
                        // minus 1 to account for the fact  that string 1 is (0 * string separation)
                        dotToBeMoved.left = 1 + ((dotCounter - 1) * this.StringSeparationEdit)
                    }
                }
            }
        }
        else if (this.DropElement.id.indexOf(this.OwnerPrefix + "ToolBarNumber") != -1) 
        {
            // its the draggable number image
            //TODO: these values are also set in the code behind of ChordBox which need to be centralised not reproduced
            this.DropElement.style.left = this.ToolBarNumberLeft;

            if (this.DropElement.getAttribute('Number') == 'X' || this.DropElement.getAttribute('Number') == 'O') 
            {
                // we are positioning a special 'Number'
                //alert('Reset Element: ImageNumberDropped: ' + numberImage.getAttribute('Number'));
                // we are resetting the X or O tool bar number:
                this.DropElement.style.top = this.DropElement.getAttribute('Number') == 'X' ? "15px" : "1px";
                this.DropElement.style.left = this.ToolBarNumberLeft;
            }
            else if (this.DropElement.getAttribute('Number') == 'T')
            {
                // its a special 'number'
                this.DropElement.style.top = ((5 * this.ToolBarNumberSeparation) + 40) + "px";
            }
            else 
            {
                // its a normal Number
                this.DropElement.style.top = ((this.DropElement.getAttribute('Number') * this.ToolBarNumberSeparation) + 40) + "px";
            }
        }
    },
    
    
    
    
    
    
    
    
    
    
    
    FindString : function ()
    {
        var counter;
        var stringNumber = 0;        
        for (counter = 0; counter < 6; counter ++)
        {
            var StringPixelPosition = counter * this.StringSeparationEdit;
            var Variance = this.StringSeparationEdit / 2;

            // if the center of the dot is within half a dots width either side of the string it is considered on the string for positioning
            if ((this.CenterLeft >= (StringPixelPosition - Variance)) && (this.CenterLeft <= (StringPixelPosition + Variance)))
            {
                Log('FindString->StringNumber->' + (counter + 1));
                return counter + 1;
            }
        }
        Log('FindString->String Not Found');
        return -1;
    },
    
    
    
    FindFret : function()
    {
        var fretNumber
        for (fretNumber = 0; fretNumber < 5; fretNumber ++) 
        {            
            // y has a max of 4 as that is the number of frets we are allowing access to on the chord box
            var topLimit = (fretNumber - 1) * this.FretHeightEdit;
            var bottomLimit = fretNumber * this.FretHeightEdit;

            if (this.CenterTop >= topLimit && this.CenterTop <= bottomLimit)
            {
                Log('FindFret->FretNumber->' + fretNumber);
                return fretNumber;
            }
        }        
        Log('FindFret->Fret Not Found');
        return -1;  
    },
    
    
    
    
    GetNewImage : function(imageNumber, verticalPosition, horizontalPosition)
    {
        Log('GetNewImage->');
        
        //??????????????????????????????????????????????????????????????????????????????????????????????????????????
        // IS THE NAME OF THIS WRONG - DOES NUMBER_STRING GET PARSED TO FIND THE NUMBER OF THE IMAGE LATER????????
        //??????????????????????????????????????????????????????????????????????????????????????????????????????????

        var newItemId = 'Number_String_Dropped' + NewItemCounter;
        
        if (this.Browser == 'FIREFOX')
        {        
            var newImage = document.createElement('img');
            newImage.setAttribute('id', newItemId);
            newImage.setAttribute('name', newItemId);
            newImage.setAttribute('alt', imageNumber);
            newImage.setAttribute('src', strThemeRootPath + "/" + imageNumber + ".gif");
            newImage.setAttribute('Number', imageNumber);
            newImage.setAttribute('OwnerPrefix', this.OwnerPrefix);
            newImage.setAttribute('ImgNumber', imageNumber);
            newImage.setAttribute('HorizontalPosition', horizontalPosition);
            newImage.setAttribute('VerticalPosition', verticalPosition);
            newImage.setAttribute('ItemType', 'Chord');
            newImage.setAttribute('drag', 'true');
            newImage.setAttribute('style', 'position:absolute;top:0px;left:0px;visibility:visible;z-index:99999');        
            var parent = document.getElementById(this.OwnerPrefix + 'spanNewChordItem');
            parent.insertBefore(newImage, null);
        }
        else
        {
            var newItemOuterHtml = "<IMG id='" + newItemId 
                                    + "' name='" + newItemId 
                                    + "' alt='" + imageNumber 
                                    + "' src='" + strThemeRootPath + "/" + imageNumber + ".gif'" 
                                    + "  Number='" + imageNumber 
                                    + "' ImgNumber='" + imageNumber
                                    + "' OwnerPrefix='" + this.OwnerPrefix 
                                    + "' drag='true' ImgNumber='" + imageNumber 
                                    + "' HorizontalPosition='" + horizontalPosition 
                                    + "' VerticalPosition='" + verticalPosition 
                                    + "' ItemType='Chord' Style='position:absolute;top:0px;left:0px;height:10px;width:10px;visibility:visible;z-index:99999' />";

            document.getElementById(this.OwnerPrefix + 'spanNewChordItem').outerHTML = "<span id='" + this.OwnerPrefix + "spanNewChordItem'></span>" + newItemOuterHtml;
        }

        NewItemCounter++;

        Log('GetNewImage->end');
        return document.getElementById(newItemId);
    },
    
    
    
    SetPositionDot : function(divElement, bUseSmallSizing)
    {
        Log('SetPositionDot->');
        
        //TODO: the hard coded sizing values in this function need to be centralised with those from DropContainer

        var intStringNumber = divElement.getAttribute('String');
        var intFretNumber = divElement.getAttribute('Fret');
        var intHalfDotWidth = (parseInt(eval("document.forms[0]." + divElement.id + ".style.width")) / 2);


        var aestheticCompensate;
        var stringSeparation;
        var fretHeight;

        if (bUseSmallSizing) 
        {
            // we are using the small chord background
            aestheticCompensate = this.AestheticDotCompensateView;
            stringSeparation = this.StringSeparationView;
            fretHeight = this.FretHeightView;
        }
        else 
        {
            // we are using the large chord background for edit mode
            aestheticCompensate = this.AestheticDotCompensateEdit;
            stringSeparation = this.StringSeparationEdit;
            fretHeight = this.FretHeightEdit;
        }


        var top, left;
        top = ((intFretNumber * fretHeight) - intHalfDotWidth - aestheticCompensate) + "px";
        left = (((intStringNumber - 1) * stringSeparation) - intHalfDotWidth + 1) + "px";
        
//        Log('SetPositionDot->top->' + top);
//        Log('SetPositionDot->left->' + left);

        divElement.style.top = top;
        divElement.style.left = left; 	
        // intStringNumber - 1 because string 1 is not 1 strings distance in ,it is 0 string distances in. also, the -1 at the end is to account for the half dot width position
    },
    
    
    
    
    SetDataDot : function(fretNumber, stringNumber)
    {
        Log('SetDataDot->');
        
        // first make sure the dot isnt already there:
        this.RemoveDataDot(stringNumber);

        var mainItems = this.HiddenField.value.split(':');
        var strOldName = mainItems[0];
        // this is an array of the form string-number, string-number, string-number
        var arrDots = mainItems.length >= 2 ? mainItems[1].split('|') : null; 
        // this is an array of the form string-number, string-number, string-number
        var arrNumbers = mainItems.length >= 3 ? mainItems[2].split('|') : null; 
        var fret = mainItems[3] ? mainItems[3] : '';

        arrDots = AddToArray(arrDots, stringNumber, fretNumber, '-');

        // set the new value of the hidden field to that of the new array without the extra item present:
        this.HiddenField.value = strOldName + ':' + ArrayToString(arrDots, '|') + ':' + ArrayToString(arrNumbers, '|') + ':' + fret;
        
        // just as a safety check make sure we have no '|' lurking where we shouldnt:
        this.HiddenField.value = this.HiddenField.value.replace('|:', ':');
        this.HiddenField.value = this.HiddenField.value.replace(':|', ':');
    },
    
    
    
    RemoveDataDot : function(stringNumber)
    {
        Log('RemoveDataDot->');
        Log('RemoveDataDot->StringNumber->' + stringNumber);
        
        // we can only do this if we have some hidden data to remove from:
        if (this.HiddenField.value.length > 0)
        {
            var mainItems = this.HiddenField.value.split(':');

            // we can only do this if there is already data present in the hiddenField - otherwise there's noting to remove from
            if (mainItems.length > 0)
            {
                var strOldName = mainItems[0];
                // this is an array of the form string-number, string-number, string-number
                var arrDots = mainItems.length >= 2 ? mainItems[1].split('|') : null; 
                // this is an array of the form string-number, string-number, string-number
                var arrNumbers = mainItems.length >= 3 ? mainItems[2].split('|') : null; 
                var fret = mainItems[3] ? mainItems[3] : '';

                arrDots = RemoveArrayItemStartingWithChar(arrDots, stringNumber);

                // set the new value of the hidden field to that of the new array without the extra item present:
                this.HiddenField.value = strOldName + ':' + ArrayToString(arrDots, '|') + ':' + ArrayToString(arrNumbers, '|') + ':' + fret;
            }
        }
    },
    
    
    
    SetPositionNumber : function(divElement, bUseSmallVersion)
    {
        Log('SetPositionNumber->');
    
        var intStringNumber = divElement.getAttribute('String');
        var intHalfNumberWidth = parseInt(divElement.width) / 2;
        var intNumberVerticalPosition;
        
        Log('SetPositionNumber->StringNumber->' + intStringNumber);
        
        Log('SetPositionNumber->Left->' + left);

        if (divElement.style.visibility == 'hidden')
            return;
            
        
        var stringSeparation;
        
        if (bUseSmallVersion)
            stringSeparation = this.StringSeparationView;
        else
            stringSeparation = this.StringSeparationEdit;
        
        // the horizontal position will be constant for whatever is dropped
        var left = ((intStringNumber - 1) * stringSeparation) - intHalfNumberWidth + 1;

        if (divElement.getAttribute('Number') == 'X' || divElement.getAttribute('Number') == 'O') 
        {
            // we are positioning a special 'Number'
            Log('SetPosotionNumber->SpecialNumber->' + divElement.getAttribute('Number'));
            
            if (bUseSmallVersion)            
                intNumberVerticalPosition = this.SpecialNumberTopView;
            else
                intNumberVerticalPosition = this.SpecialNumberTopEdit;

            divElement.style.top = intNumberVerticalPosition;
            divElement.style.left = left + 'px';
            
            Log('SetPositionNumber->divElementLeft->' + divElement.style.left);
            Log('SetPositionNumber->divElementTop->' + divElement.style.top);
        }
        else 
        { 
            // its a normal Number
            Log('SetPositionNumber->Normal Number->' + intStringNumber);
            
            if (bUseSmallVersion)            
                intNumberVerticalPosition = this.NumberTopView;
            else
                intNumberVerticalPosition = this.NumberTopEdit;

            Log('SetPositionNumber->Left->' + left);
            divElement.style.top = intNumberVerticalPosition;
            divElement.style.left = left + 'px';
            
            Log('SetPositionNumber->divElementLeft->' + divElement.style.left);
            Log('SetPositionNumber->divElementTop->' + divElement.style.top);
        }        
    },
    
    
    
    SetDataNumber : function(stringNumber, number)
    {
        Log('SetDataNumber->');
        Log('SetDataNumber->StringNumber->' + stringNumber);
        Log('SetDataNumber->Number->' + number);

        var mainItems = this.HiddenField.value.split(':');
        var strOldName = mainItems[0];
        // this is an array of the form string-number, string-number, string-number
        var arrDots = mainItems.length > 2 ? mainItems[1].split('|') : null; 
        // this is an array of the form string-number, string-number, string-number
        var arrNumbers = mainItems.length > 2 ? mainItems[2].split('|') : null; 
        var fret = mainItems[3] ? mainItems[3] : '';
        
        arrNumbers = AppendToArray(arrNumbers, stringNumber, number, '-');

        Log('ArrDots->' + ArrayToString(arrDots, '|'));

        // set the new value of the hidden field to that of the new array without the extra item present:
        this.HiddenField.value = strOldName + ':' + ArrayToString(arrDots, '|') + ':' + ArrayToString(arrNumbers, '|') + ':' + fret;

        // just as a safety check make sure we have no '|' lurking where we shouldnt:
        this.HiddenField.value = this.HiddenField.value.replace('|:', ':');
        this.HiddenField.value = this.HiddenField.value.replace(':|', ':');
    },
    
    
    
    RemoveDataNumber : function(stringNumber, number)
    {
        Log('RemoveDataNumber->');
        
        if (this.HiddenField.value == '')
            return;
            
        var strNumbers = this.HiddenField.value.split(':')[2];
        Log('RemoveDataNumber->StrNumbers->' + strNumbers);
        
        if (strNumbers.indexOf(stringNumber + '-') == -1)
        {
            Log('RemoveDataNumber->Return as stringNumber"' + stringNumber + '"' + ' not found');
            return;
        }
        
        if ((number >= 1 && number <= 4) || number == 'T')
        {
            Log('RemoveDataNumber->Remove Normal Number');
            
            var arrRemoveItems = new Array('1', '2', '3', '4', 'T');
            var arrNewNumbersArray = RemoveValuesFrom2dArray(strNumbers.split('|'), stringNumber, arrRemoveItems);
        }
                
        if (number == 'X' || number == 'O')
        {
            Log('RemoveDataNumber->Remove Special Number');
            
            var arrRemoveItems = new Array('X', 'O');
            var arrNewNumbersArray = RemoveValuesFrom2dArray(strNumbers.split('|'), stringNumber, arrRemoveItems);
        }
            
        
        // save the array        
        var mainItems = this.HiddenField.value.split(':');
        this.HiddenField.value = mainItems[0] + ':' + mainItems[1] + ':' + ArrayToString(arrNewNumbersArray, '|') + ':' + mainItems[3];
        
        Log('RemoveDataNumber->HiddenFieldValue->' + this.HiddenField.value);
    },
    
    
    
    HideNumberByPosition : function(stringNumber, number)
    {
        Log('HideNumberByPosition->');
        
        var strNumbers = this.HiddenField.value.split(':')[2];
        var allowedNumbers;
        
        if ((number >= 1 && number <= 4) || number == 'T')
        {
            allowedNumbers = '1,2,3,4,T';
        }
        else if (number == 'X' || number == 'O')
        {
            // if there is a special number on the string already it needs to be hidden
            allowedNumbers = 'X,O';
        }   
        
        // if there is a number on the string already it needs to be hidden
        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('id').indexOf('Number_String') != -1)
                {
                    if (document.images[i].id == 'Number_String_Dropped' + (NewItemCounter - 1))
                    {
                        // continue or we'll hide the image we're dropping
                        continue;
                    }
                        
                    // if its a dropped number already on the grid:
                    var imagesString, imagesNumber;
                    imagesString = document.images[i].getAttribute('String');
                    imagesNumber = document.images[i].getAttribute('ImgNumber');
                    
                    Log('HideNumberByPosition->imagesString->' + imagesString + '  stringNumber->' + stringNumber);
                    Log('HideNumberByPosition->imagesNumber->' + imagesNumber);
                    Log('HideNumberByPosition->id->' + document.images[i].id);
                    
                    // if the string and number match then make it invisible
                    if (imagesString == stringNumber && allowedNumbers.indexOf(imagesNumber) != -1)
                    {
                        Log('HideNumberByPosition->Hiding image with id->' + document.images[i].id);
                        document.images[i].style.visibility = 'hidden';
                    }
                }
            }
        }
    }
    
    
}