/* Copyright 2006 Microsoft Corporation.  Microsoft's copyrights in this work are licensed under the Creative Commons */
/* Attribution-ShareAlike 2.5 License.  To view a copy of this license visit http://creativecommons.org/licenses/by-sa/2.5 */


var ControlsOnPage = new Array();


WebClip = function(clipBoardControlContainer, copyCallback, pasteCallback, onControlSelected, onControlDeSelected) 
{
    // Populate the input container (usually a div) with control container w/ input.
    
    var self = this;
    var clipBoardControlInput = document.createElement("input");
    clipBoardControlInput.className = "CopyPasteInput";
    clipBoardControlInput.setAttribute("autocomplete", "off");
    
    clipBoardControlInput.value = "intialValueToHideCursor";
    var lastKnownClipBoardValue = clipBoardControlInput.value;
        
    this.controlSelectedCallback = onControlSelected;
    this.controlDeSelectedCallback = onControlDeSelected;
    this.clickSelected = false;    
    
    this.controlDiv = document.createElement("div");
    this.controlDiv.className = "webClipControlDiv";
    this.controlDiv.appendChild(clipBoardControlInput);
    clipBoardControlContainer.appendChild(this.controlDiv);
       
    ControlsOnPage[ControlsOnPage.length] = self;
    
    var pauseInputCheck = false;
 
    this.PrepareForCopyPaste = function()
    {
        //document.getElementById("debugOutput").innerHTML += ("<br/>PrepareForCopyPaste: " + clipBoardControlContainer.id);
        pauseInputCheck = true;
        clipBoardControlInput.value = self.serializeWebClipboard(copyCallback());
        lastKnownClipBoardValue = clipBoardControlInput.value;
        pauseInputCheck = false;

        //selectAllText(clipBoardControlInput);
        clipBoardControlInput.select();
    }
    
    this._onClick = function(e)
    {
        // Have to register onclick separately in Mozilla, because the text selection is unpredictable with left click (puts a cursor
        // in the input instead of select all every other time).
        
        self.PrepareForCopyPaste();
        
        for (var i = 0; i < ControlsOnPage.length; i++) 
        {
            ControlsOnPage[i].clickSelected = false;
            ControlsOnPage[i].controlDiv.className = "webClipControlDiv";
            ControlsOnPage[i].controlDeSelectedCallback()
        }
        
        self.clickSelected = true;
        self.controlDiv.className = "webClipControlSelectedDiv";
        self.controlSelectedCallback();
    }
    
    this._onMouseDown = function(e)
    {
        if (!e) 
        {
            e = window.event;
        }
        
        if (e.button == 2)
        {        
            self.PrepareForCopyPaste();
            
            for (var i = 0; i < ControlsOnPage.length; i++) 
            {
                if (ControlsOnPage[i].clickSelected)
                {
                    ControlsOnPage[i].clickSelected = false;
                    ControlsOnPage[i].controlDiv.className = "webClipControlDiv";
                    ControlsOnPage[i].controlDeSelectedCallback()
                }
            }
            
            self.clickSelected = true;
            self.controlDiv.className = "webClipControlSelectedDiv";
            self.controlSelectedCallback();
        }
    }
    
    this._onMouseUp = function(e)
    {
        if (!e) 
        {
            e = window.event;
        }
        
        // Don't leave selected for right-click.
        // The input will still be active.  If it is unselected here, copy/paste from the context menu won't work, 
        //         because this event fires before the menu is drawn.
        if (e.button == 2)
        {
            self.clickSelected = false;
            self.controlDiv.className = "webClipControlDiv";
            self.controlDeSelectedCallback();
        }        
    }
    
    this._onFocus = function(e)
    {
        self.clickSelected = true;
        self.controlDiv.className = "webClipControlSelectedDiv";
        self.controlSelectedCallback();
    }
    
    this._onBlur = function(e)
    {
        self.clickSelected = false;
        self.controlDiv.className = "webClipControlDiv";
        self.controlDeSelectedCallback();
    }
    
    this.checkInputValue = function()
    {
        if (!pauseInputCheck && (clipBoardControlInput.value != lastKnownClipBoardValue))
        {
            lastKnownClipBoardValue = clipBoardControlInput.value;
            clipBoardControlInput.blur();
            self.handlePastedData(lastKnownClipBoardValue);
        }

        window.setTimeout(self.checkInputValue, 50);
    }
    
    this.handlePastedData = function(dataString)
    {
        var clipData = self.parseWebClipboardXml(dataString);
        pasteCallback(clipData);
    }
    
    this.serializeWebClipboard = function(clipData)
    {
        var xmlString = "<?xml version=\"1.0\" encoding=\"utf-8\" ?><liveClipboard version=\"1.0\" xmlns:lc=\"http://www.microsoft.com/schemas/live\">";
        
        if (clipData.dataFormats)
        {
            for (var i = 0; i < clipData.dataFormats.length; i++)
            {
                xmlString += "<lc:format type=\"" + clipData.dataFormats[i].type + ((clipData.dataFormats[i].link == null) ? "" : ("\" ref=\"" + clipData.dataFormats[i].link + "")) + "\">";
                
                for (var j = 0; j < clipData.dataFormats[i].items.length; j++)
                {
                    xmlString += clipData.dataFormats[i].items[j].data;
                }
                
                xmlString += "</lc:format>";
            }
        }
        
        if (clipData.feeds)
        {
            for (var i = 0; i < clipData.feeds.length; i++)
            {
                xmlString += "<lc:format type=\"" + clipData.feeds[i].feedType + "\" " + ((clipData.feeds[i].link == null) ? "" : ("ref=\"" + clipData.feeds[i].link + "\"")) + ">";
                xmlString += "<lc:feed Description=\"" + clipData.feeds[i].description + "\" itemType=\"" + clipData.feeds[i].itemType + "\" authType=\"" + clipData.feeds[i].authType + "\">";
                
                if (clipData.feeds[i].itemIds.length > 0)
                {
                    xmlString += "<lc:feedItemMap>";
                    
                    for (var j = 0; j < clipData.feeds[i].itemIds.length; j++)
                    {
                        xmlString += "<lc:itemId>" + clipData.feeds[i].itemIds[j] + "</lc:itemId>";
                    }
                    
                    xmlString += "</lc:feedItemMap>";
                }
                xmlString += "</lc:feed>";
                xmlString += "</lc:format>";
            }
        }
                
        xmlString += "</liveClipboard>";
        
        return xmlString;
    }
    
    this.parseWebClipboardXml = function(xmlString) 
    {
        // Undone: catch exceptions and return empty clipData?
        var xmlDocument;
        var clipData = new WebClipData();
      try {
        
        if ((xmlString != null) && (xmlString != "")) 
        {
            // IE 5+
            if (window.ActiveXObject)
            {
                xmlDocument = new ActiveXObject("Microsoft.XMLDOM");
                xmlDocument.async=false;
                xmlDocument.loadXML(xmlString);
                clipData.version = xmlDocument.selectSingleNode("/liveClipboard/@version").nodeTypedValue;
                var formatNodes = xmlDocument.selectNodes("/liveClipboard/lc:format");
                
                for (var i = 0; i < formatNodes.length; i++)
                {
                    var feedNode = formatNodes[i].selectSingleNode("lc:feed");
                    
                    if (feedNode != null)
                    {
                        var feed = new WebClipFeed();
                        feed.feedType = formatNodes[i].selectSingleNode("@type").nodeTypedValue;
                        feed.description = feedNode.selectSingleNode("@Description").nodeTypedValue;
                        feed.itemType = feedNode.selectSingleNode("@itemType").nodeTypedValue;
                        feed.authType = feedNode.selectSingleNode("@authType").nodeTypedValue;
                        feed.link = formatNodes[i].selectSingleNode("@ref").nodeTypedValue;
                        var itemMapNodes = feedNode.selectNodes("lc:feedItemMap/lc:itemId");
                        
                        for (var j = 0; j < itemMapNodes.length; j++)
                        {
                            feed.itemIds[j] = itemMapNodes[j].nodeTypedValue;
                        }
                        
                        clipData.feeds[clipData.feeds.length] = feed;
                    }
                    else
                    {
                        var format = new WebClipDataFormat();
                        format.type = formatNodes[i].selectSingleNode("@type").nodeTypedValue;
                        var linkNode = formatNodes[i].selectSingleNode("@ref");
                        
                        if (linkNode)
                            format.link = linkNode.nodeTypedValue;
                            
                        format.items[0] = new WebClipDataItem();
                        format.items[0].data = formatNodes[i].nodeTypedValue;                       
                        clipData.dataFormats[clipData.dataFormats.length] = format;
                    }
                }
                
                return clipData;
            }
            // Mozilla etc.
            else if (typeof DOMParser != "undefined")
            {
                var domParser = new DOMParser();
                var xmlDocument = domParser.parseFromString(xmlString, 'application/xml');
                    
                if (document.evaluate)
                {
                    clipData.version = document.evaluate("/*/@version", xmlDocument, resolveNamespace, 0 /*XPathResult.ANY_TYPE*/, null).iterateNext().nodeValue;
                    var formatNodeResult = document.evaluate("/*/lc:format", xmlDocument, resolveNamespace, 0 /*XPathResult.ANY_TYPE*/, null);
                    var formatNode = formatNodeResult.iterateNext();
                    
                    while (formatNode)
                    {
                        var feedNodeResult = document.evaluate("lc:feed", formatNode, resolveNamespace, 0 /*XPathResult.ANY_TYPE*/, null);
                        var feedNode = feedNodeResult.iterateNext();
                        
                        if (feedNode)
                        {
                            var feed = new WebClipFeed();
                            feed.feedType = feedNode.parentNode.getAttributeNode("type").nodeValue;
                            feed.description = feedNode.getAttributeNode("Description").nodeValue;
                            feed.itemType = feedNode.getAttributeNode("itemType").nodeValue;
                            feed.authType = feedNode.getAttributeNode("authType").nodeValue;
                            feed.link = formatNode.getAttributeNode("ref").nodeValue;
                            var itemMapNodesResult = document.evaluate("lc:feedItemMap/lc:itemId", feedNode, resolveNamespace, 0 /*XPathResult.ANY_TYPE*/, null)
                            var itemMapNode = itemMapNodesResult.iterateNext();
                            
                            while (itemMapNode)
                            {
                                feed.itemIds[feed.itemIds.length] = itemMapNode.nodeValue;
                                itemMapNode = itemMapNodesResult.iterateNext();
                            }
                            
                            clipData.feeds[clipData.feeds.length] = feed;
                         }
                        else
                        {
                            var format = new WebClipDataFormat();
                            format.type = formatNode.getAttributeNode("type").nodeValue;
                            var linkNode = formatNode.getAttributeNode("ref");
                            
                            if (linkNode)
                                format.link = linkNode.nodeValue;
                            
                            format.items[0] = new WebClipDataItem();
                            format.items[0].data = formatNode.textContent;
                            clipData.dataFormats[clipData.dataFormats.length] = format;
                        }
                        
                        formatNode = formatNodeResult.iterateNext();
                    }
                }
                else
                {
                    for (var i = 0; i < xmlDocument.childNodes.length; i++)
                    {
                        if (xmlDocument.childNodes[i].nodeName == "liveClipboard")
                        {
                            for (var j = 0; j < xmlDocument.childNodes[i].attributes.length; j++)
                            {
                                if (xmlDocument.childNodes[i].attributes[j].nodeName == "version")
                                    clipData.version = xmlDocument.childNodes[i].attributes[j].nodeValue;
                            }
                            
                            for (var j = 0; j < xmlDocument.childNodes[i].childNodes.length; j++)
                            {
                                if (xmlDocument.childNodes[i].childNodes[j].nodeName == "lc:format")
                                {
                                    // undone: see if it's a feed.
                                    var format = new WebClipDataFormat();
                                    
                                    for (var k = 0; k < xmlDocument.childNodes[i].childNodes[j].attributes.length; k++)
                                    {
                                        if (xmlDocument.childNodes[i].childNodes[j].attributes[k].nodeName == "type")
                                            format.type = xmlDocument.childNodes[i].childNodes[j].attributes[k].nodeValue;
                                        
                                        if (xmlDocument.childNodes[i].childNodes[j].attributes[k].nodeName == "ref")
                                            format.link = xmlDocument.childNodes[i].childNodes[j].attributes[k].nodeValue;
                                    }
                                    
                                    if (xmlDocument.childNodes[i].childNodes[j].childNodes.length == 1)
                                    {
                                        format.items[0] = new WebClipDataItem();
                                        format.items[0].data = xmlDocument.childNodes[i].childNodes[j].childNodes[0].nodeValue;
                                        clipData.dataFormats[clipData.dataFormats.length] = format;
                                    }                              
                                }
                            }
                        }
                    }
                }
            }
        }
      } catch (e) {}

        return clipData;
    }
    
    clipBoardControlInput.onmousedown = self._onMouseDown;
    clipBoardControlInput.onmouseup = self._onMouseUp;
    clipBoardControlInput.onclick = self._onClick;
    clipBoardControlInput.onfocus = self._onFocus;
    clipBoardControlInput.onblur = self._onBlur; 
        
    clipBoardControlInput.blur();
    window.setTimeout(self.checkInputValue, 50);
}


function setSelectionRange(input, begin, end) 
{
    if (input.setSelectionRange) {
        input.focus();
        input.setSelectionRange(begin, end);
    }
    else if (input.createTextRange) 
    {
        var range = input.createTextRange();
        range.collapse(true);
        range.moveEnd('character', selectionEnd);
        range.moveStart('character', selectionStart);
        range.select();
    }
}
function selectAllText(input)
{
    setSelectionRange(input, 0, input.value.length);
}

function resolveNamespace(prefix) 
{
    if(prefix == "lc") 
    {
      return "http://www.microsoft.com/schemas/live";
    }

    return null;
}

WebClipData = function()
{
    this.version = "1.0";
    this.dataFormats = new Array();
    this.feeds = new Array;
}

WebClipDataFormat = function() 
{
    this.type;
    this.link;
    this.items = new Array;
}

WebClipDataItem = function()
{
    this.data;
    this.xmlData;
}

WebClipFeed = function()
{
    this.feedType;
    this.description;
    this.itemType;
    this.authType;
    this.link;
    this.itemIds = new Array();
}



