var bodyId="contextArea";
var currentOffset = null; // for draggable
var targetDrawable = null;
var targetXPos = null;
var ctrlDown = false;
var selectedDrawables = new Array();
var copiedDrawables = new Array();
var cuttedDrawables = new Array();
var yPosOffset = 113;
var bgClass = "note_bg";
var menuClass = "menu";
var lockCursor = false;
var targetArea = null;
var leftMargin = 10;
var partitionOverlayClass = "npartition";
var partitionOverlayImg = "/images/partOL.gif";
var partitionWidth = 128;
var partitionHeight = 128;
var stemUpInDep = "ui";
var stemUpDep = "ud";
var stemDownInDep = "di";
var stemDownDep = "dd";
var validNoteRe = /(n\d+_\d+_\d+_\d+(_ui|_ud|_di|_dd|))/;

var highlightedNotes = new Array();


var PITCH_DISTANCE = 7;
var PAGE_TOP_MARGIN = (4 * PITCH_DISTANCE);
var TOP_MARGIN = 12 * PITCH_DISTANCE;
var TOP_LINE = PAGE_TOP_MARGIN + TOP_MARGIN;
var FORBIDDEN_EDGE = 160;
var NOTE_HEIGHT = (PITCH_DISTANCE * 8) - 4;
var DECORATION_EPSILON = 625;
var targetNotes = new Array();
var noteIds = new Array();
function rebuildNoteInfomations(){
    noteIds.clear();
    targetNotes = new Array();    
    $$("AREA").each(function(element){
        var tg_ = new TargetArea(element);
        if(tg_.isValid()){
            targetNotes.push(tg_);
            noteIds.push(tg_.noteId);
            Background.create(tg_);
        }
    });
    noteIds = noteIds.uniq();
    Background.hideAll();
}

function showDecor(event, draggable){
    try{
        var clientX = event.clientX;
        var clientY = event.clientY;
        var offsetX = draggable.offset[0];
        var offsetY = draggable.offset[1];
        var posTop = topPos();
        var posLeft = leftPos();
        
        var finalXPos = Math.max(clientX - offsetX + posLeft, FORBIDDEN_EDGE);
        var finalYPos = clientY - offsetY + posTop;
        var nearestNote = findNoteForDecor(finalXPos, finalYPos);
        Background.hideAll();
        if(nearestNote && nearestNote.noteType <= 8){
            Background.show(nearestNote.noteId);
        }        
    }catch(e){
    $("msg_tag").innerHTML = e;
}
}

function findNoteForDecor(left, top){
    try{
        var _left = parseInt(left);
        var _top = parseInt(top - TOP_LINE);
        var nearestNote = null;
        var smallestDist = 1000000;
        targetNotes.each(function(tg){
            var y = tg.yPos;
            if(tg.stemDir == stemDownDep || tg.stemDir == stemDownInDep){
                y += NOTE_HEIGHT;
            }
            var thisDistSqr = Math.pow(tg.xPos - _left, 2) + Math.pow(y- _top, 2);
            if(thisDistSqr < smallestDist){
                smallestDist = thisDistSqr;
                nearestNote = tg;
            }
        });
        return smallestDist < DECORATION_EPSILON ? nearestNote : null;
    }catch(e){
    $("msg_tag").innerHTML = e;
}

}

Array.prototype.unique =
  function() {
    var a = [];
    var l = this.length;
    for(var i=0; i<l; i++) {
      for(var j=i+1; j<l; j++) {
        // If this[i] is found later in the array
        if (this[i] === this[j])
          j = ++i;
      }
      a.push(this[i]);
    }
    return a;
  };
var TargetArea = Class.create();
TargetArea.prototype = {
    initialize: function(element) {
        this.resetAttributes();
        if(element.tagName == "AREA" && validNoteRe.test(element.className)){
            var matchClass = validNoteRe.exec(element.className)[1];
            var attrs = matchClass.split("_");
            this.noteId = attrs[0];
            this.noteType = parseInt(attrs[1]);
            this.xPos = parseInt(attrs[2]);
            this.yPos = parseInt(attrs[3]);
            this.stemDir = attrs[4];
            //      this.stemDir = (attrs[4] == "u" ? stemUp : stemDown);
            this.targetElement = element;
        }
    },
    resetAttributes: function(){
        this.targetElement = null;
        this.noteId = null;
        this.noteType = 0;
        this.xPos = 0;
        this.yPos = 0;
        this.stemDir = stemUpInDep;
    },
    isValid: function(){
        var vName = /^n\d+$/.test(this.noteId);
        var vType = (this.noteType > 0 && this.noteType <=13);
        var vXPos = (this.xPos >= 0);
        var vYPos = (this.yPos >= 0);
        return(vName && vType && vXPos && vYPos);
    },
    bgXPos: function(){
        var x = this.xPos;
        switch(this.noteType){
            case 1:
            x += 8;
            break;
            case 2:
            case 3:
            case 4:
            if(this.stemDir == stemUpInDep || this.stemDir == stemUpDep){
                x += 5;
            }else if(this.stemDir == stemDownDep){
            x += 6;
        }else{
        x += 14;
    }
    break;
    case 5:
    case 6:
    case 7:
    case 8:
    x += 9;
    break;
    case 13:
    x -= 2;
    break;
}
return x + "px";
},
bgYPos: function(){
    var y = this.yPos + yPosOffset;
    switch(this.noteType){
        case 1:
        y += 2;
        break;
        case 2:
        case 3:
        case 4:
        if(this.stemDir == stemDownDep || this.stemDir == stemDownInDep){
            y += 2;
        }
        break;
        case 5:
        y += 22;
        break;
        case 6:
        y += 19;
        break;
        case 7:
        case 8:
        y += 10;
        break;
        case 13:
        y +=50;
        break;
    }
    return y + "px";
}
};
var Background = Class.create();

Background.hide = function(noteId){
    var bg = Background.get(noteId);
    if(bg){
        bg.hide();
        var index = highlightedNotes.indexOf(noteId);
        if( index > -1){
            highlightedNotes.splice(index, 1);
        }
    }
}
Background.hideAll = function(){
    highlightedNotes.each(function(noteId){
        Background.hide(noteId);
    })
}
Background.show = function(noteId){
    var bg = Background.get(noteId);
    if(bg){
        bg.show();
        if(highlightedNotes.indexOf(noteId) < 0){
            highlightedNotes.push(noteId);
        }
    }
}
Background.get = function(noteId){
    return $("note_" + noteId + "_bg");
};
Background.remove = function(noteId){
    var bg = Background.get(noteId)
    if(bg){
        bg.remove();
    }
};
Background.setPosition = function(noteId, target){
    var bg = Background.get(noteId);
    if(bg){
        bg.style.left = target.bgXPos();
        bg.style.top = target.bgYPos();
    }
};
Background.create = function(target){
    noteId = target.noteId
    Background.remove(noteId);
    note = document.createElement("div");
    note.setAttribute("id", "note_" + noteId + "_bg");
    note.className = "note_" + target.noteType + "_bg" + " note_bg " + target.targetElement.className;
    var styleText = "display: none;";
    if(target.noteType == 13){
        styleText += "background-repeat: repeat-y; height: 218px;";
    }
    note.setAttribute("style", styleText);
    note.style.cssText = styleText;
    document.body.appendChild(note);
    Background.setPosition(noteId, target);
};

function rebuildPartitionArea(){
    // Remove all the new partitions and recreate it base on the old partitions.
    var notes = $("notes");
    $$("." + partitionOverlayClass).each(function(np){
        Element.remove(np);
    });
    if(notes){
        notes.childElements().each(function(part){
            var re = /part(\d+_\d+)/;
            
            if(re.test(part.id)){
                var id = re.exec(part.id)[1];
                var map = $("map" + id);
                if(map){
                    img = document.createElement("img");
                    img.setAttribute("id", "npart" + id);
                    img.className = partitionOverlayClass; //Can't set the class by setAttribute for IE
                    img.setAttribute("src", partitionOverlayImg);
                    img.setAttribute("width", partitionWidth);
                    img.setAttribute("height", partitionHeight);
                    img.setAttribute("usemap", "#map" + id, 0);
                    var left = (parseInt(part.style.left) + leftMargin) + "px";
                    var top = part.style.top;
                    var styleText = "position:absolute; left:" + left +"; top:" + top +"; border: none; z-index: 3;";
                    img.setAttribute("style", styleText);
                    img.style.cssText = styleText;
                    document.body.appendChild(img);
                }
            }
        });
    }else{
    alert("Something wrong in rebuild partition area! Please call Daniel!");
}
}


function checkKeycode(event) {
    var keyCode = getKeyCode(event);
    switch(keyCode){
        case 13:
        void(0);
        break;
        case 46:
        deleteDrawables();
        break;
    }
}

function getKeyCode(event){  
    if(window.event){
        return window.event.keyCode;
    }
    else if(event){
        return event.which;
    }
}

function deleteDrawables(){
    if(selectedDrawables.length > 0){
        var ids = new Array();
        selectedDrawables.each(function(noteId){
            if(noteId != undefined){
                ids.push(noteId);
                Background.remove(noteId);
            }
        });
        new Ajax.Request('/scores/removing/?ids=' + ids.join(","), {
            asynchronous:true,
            evalScripts:true,
            onComplete:function(request){
                eval(response.txt)
            }
        });
        resetSelectedNotes();
        copiedDrawables = new Array();
    }else{
    alert("Nothing selected");
}
}

function toggleSelectedNote(event, targetArea){
    var noteId = targetArea.noteId;    
    var index = selectedDrawables.indexOf(noteId);   
    if( index > -1){
        if(event.isLeftClick()){
            selectedDrawables.splice(index, 1);
            Background.hide(noteId);
        }
    }else{
    selectedDrawables.push(noteId);
    Background.show(noteId);
}
}

function selectNote(event, targetArea){	
    if(Background.get(targetArea.noteId)){
        Background.setPosition(targetArea.noteId, targetArea);
    }else{
    Background.create(targetArea);
}
if (event.ctrlKey){
    toggleSelectedNote(event, targetArea);
}else{
if(event.isLeftClick()){
    resetSelectedNotes();
    targetDrawable = targetArea.noteId;
}
toggleSelectedNote(event, targetArea);
}
return false;
}

function resetSelectedNotes(){
    $$("."+bgClass).each(function(e){
        e.hide();
    });
    selectedDrawables = new Array();
}

function setMove(event,targetArea) {
    var id = 'm'+targetArea.noteType;
    var left = targetArea.xPos;
    var top = targetArea.yPos;
    if (dragger != null) {
        dragger.destroy();
        dragger = null;
    }
    dragger = new Draggable(id,{
        revert:false
        ,
        change: function (draggable)
        {
            currentOffset = draggable.offset;		 
        }
    });
    
    element = $(id);
    element.show();
    
    if (ie)	{
        setUpperLeft(element, (left+5)+"px", (top+83)+"px");
        dragger.eventMouseDown();
    } else	{
    setUpperLeft(element, (left + 5)+"px", (top+93)+"px");
    globalLeft = parseInt(element.style.left)+(pitchDistance*2);
    globalTop = parseInt(element.style.top)+(pitchDistance*11);
    timerID = setTimeout("simulateMouseDown($('" + id + "'), '" + globalLeft + "' , '" + globalTop + "');", 10)
}
}

function searchFarmilyTree(element, className){
    if(element.hasClassName(className)){
        return element;
    }else{
    var p = element.getOffsetParent();
    if(p && p.tagName != "BODY" && p.tagName != "HTML"){
        return searchFarmilyTree(p, className);    
    }else{
    return false;
}
}
}

Event.observe(bodyId, 'mouseover', function(event){
    var element = Event.element(event);
    if(element.tagName == "AREA"){            
        document.body.style.cursor = "pointer";
    }else{
    if(!lockCursor){
        document.body.style.cursor = "default";
    }
}
});


function resetTarget(){
    targetDrawable = null;
    targetArea = null;
    lockCursor = false;
    moving = null;
}


function handleMouseDown(event) {
    if(event.isRightClick()){
        targetXPos = Event.pointerX(event);
    }
    var element = Event.element(event);   
    //    $("msg_tag").innerHTML = "target: " + element.tagName + " : " + element.id + " : " + element.className;
    if(!event.ctrlKey && event.isLeftClick()){
        if(!searchFarmilyTree(element, menuClass)){
            resetSelectedNotes();
        }
    }
    
    targetArea = new TargetArea(element);
    //    $("msg_tag").innerHTML = targetArea.stemDir;
    if(targetArea.isValid()){
        if(!ctrlDown&&event.isRightClick()){
            resetSelectedNotes();
        }
        selectNote(event, targetArea);
    }
    //    $("msg_tag").innerHTML+= "---Selected Drawables:"+selectedDrawables;
    ctrlDown = event.ctrlKey;
}

function handleMouseUp(event) {
    var element = Event.element(event);
    if(element.tagName == "AREA" || /note_bg/.test(element.className)){        
        resetTarget();
    }
}

/*QA need this function please don't remove it.*/

function jimmySecretSauce2(xpath, x, y, is_right) {
    temp = document.evaluate(xpath, document, null, XPathResult.ANY_TYPE,null);
    obj = temp.iterateNext();
    event = returnDispatchedMouseEvent(obj, x, y, 'mousedown', is_right);
    handleMouseDown(event);
    event = returnDispatchedMouseEvent(obj, x, y, 'mouseup', is_right);
    handleMouseUp(event);
    $("msg_tag").innerHTML+= "xpath:"+xpath+"x:"+x+"y:"+y;
}

function jimmySecretSauce(xpath, x, y) {
    jimmySecretSauce2(xpath, x, y, false);
}

Event.observe(bodyId, 'mousedown', function(event) { 
    handleMouseDown(event);
});


var moving = false;
Event.observe(bodyId, 'mousemove', function(event) {
    var element = Event.element(event); 
    //    $("msg_tag").innerHTML = "target: " + element.tagName + " :: " + element.className + " :: " + element.id;
    if(targetArea && targetArea.isValid()){
        var noteId = targetArea.noteId;
        if (!event.ctrlKey && targetDrawable == noteId && moving != noteId){
            //            $("msg_tag").innerHTML+="Moving.....:"+noteId;
            Background.hide(noteId);  
            moving = noteId;
            new Ajax.Request('/scores/removing/' + noteId, {
                asynchronous:true,
                evalScripts:true,
                onComplete:function(request){
                    eval(response.txt)
                }
            });
            setMove(event,targetArea);
            Background.remove(noteId);
            lockCursor = true;
        }
    }
});

Event.observe(bodyId, 'mouseup', function(event) {
    handleMouseUp(event);
});

Event.observe(document, 'keydown', function(event) {
    checkKeycode(event);
});

function copyDrawables(event){
    copiedDrawables = new Array();
    cuttedDrawables = new Array();
    copiedDrawables = selectedDrawables.clone();  
    $("msg_tag").innerHTML+="--Copy:"+copiedDrawables;  
}
function cutDrawables(event){
    copiedDrawables = new Array();
    cuttedDrawables = new Array();
    cuttedDrawables = selectedDrawables.clone();
}

function pasteDrawables(event){
    var cutAction = false;   
    var notes = copiedDrawables.concat(cuttedDrawables);
    var cutAction = cuttedDrawables.length > 0 ;     
    
    if(notes.length > 0){
        if(validateNotes(notes)){
          new Ajax.Request('/scores/paste_notes/?cut='+cutAction+'&xPos='+ targetXPos + '&ids=' + notes.join(","), {
              asynchronous:true,
              evalScripts:true,
              onComplete:function(request){
                  eval(response.txt)
              }
          });    
        }else{
          alert("The note(s) you want to paste has been changed, please copy it again!");
        }
        
    }
    $("msg_tag").innerHTML+="--Paste:"+copiedDrawables+"x:"+targetXPos;  
}
function validateNotes(notes){  
  return noteIds.size()==noteIds.concat(notes).uniq().size();    
}

function toggleMenuEnablements(event) {
    
    //    event.x += posRight();
    if(selectedDrawables.length > 0){
        $("copyMenuItem").className="copy enabled";
        $("cutMenuItem").className="cut enabled";
        $("deleteMenuItem").className="delete enabled";
    }else{
    $("copyMenuItem").className="copy disabled";
    $("cutMenuItem").className="cut disabled";
    $("deleteMenuItem").className="delete disabled";
}
var notes = copiedDrawables.concat(cuttedDrawables);
if(notes.length > 0){
    $("pasteMenuItem").className="paste enabled";
}else{
$("pasteMenuItem").className="paste disabled";
}
}

var myMenuItems = [
    {
        id: "copyMenuItem",
        name: "Copy",
        className: "copy",
        disabled: true,
        callback: function(event){
            copyDrawables(event);
        }
    },{
    id: "cutMenuItem",
    name: "Cut",
    className: "cut",
    disabled: true,
    callback: function(event){
        cutDrawables(event);
    }
},{
id: "pasteMenuItem",
name: "Paste",
className: "paste",
disabled: true,
callback: function(event){
    pasteDrawables(event);
}
},{
id: "deleteMenuItem",
name: 'Delete',
className: 'delete',
disabled: true,
callback: function(){
    deleteDrawables();
}
}
]
new Proto.Menu({
    selector: '#' + bodyId, // context menu will be shown when element with id of "contextArea" is clicked
    className: 'menu desktop', // this is a class which will be attached to menu container (used for css styling)
    menuItems: myMenuItems, // array of menu items
    beforeShow: function(event) {
        toggleMenuEnablements(event);
    }
})
