/* 
 * The contents of this file are subject to the Netscape Public
 * License Version 1.1 (the "License"); you may not use this file
 * except in compliance with the License. You may obtain a copy of
 * the License at http://www.mozilla.org/NPL/
 *  
 * Software distributed under the License is distributed on an "AS
 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
 * implied. See the License for the specific language governing
 * rights and limitations under the License.
 *  
 * The Original Code is Mozilla Communicator client code, released
 * March 31, 1998.
 * 
 * The Initial Developer of the Original Code is Netscape
 * Communications Corporation. Portions created by Netscape are
 * Copyright (C) 1998-1999 Netscape Communications Corporation. All
 * Rights Reserved.
 * 
 * Contributor(s): 
 *   Ben "Count XULula" Goodger
 */

/**************         FOR NOW         **************/
const TEXT_WIDGETS_DONT_SUCK  = false;
const PERFORMANCE_BOOSTS      = false;

/**************       NAMESPACES       ***************/
const XUL_NS    = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
 
/**************         GLOBALS         **************/

var tagname     = null; // element.nodeName;
var element     = null; // handle for the actual element

var HTMLAttrs   = [];   // html attributes
var CSSAttrs    = [];   // css attributes
var JSEAttrs    = [];   // js events 

var HTMLRAttrs  = [];   // removed html attributes                              
//var CSSRAttrs   = [];   // removed css attributes                               
var JSERAttrs   = [];   // removed js events                                    
                                                                                                                                                   
var gSelecting = false; // To prevent recursive selection
var dialog;

/************** INITIALISATION && SETUP **************/

/**
 * function   : void Startup();
 * parameters : none
 * returns    : none
 * desc.      : startup and initialisation, prepares dialog. 
 **/
function Startup()
{
  // This is the return value for the parent,
  // who only needs to know if OK was clicked
  window.opener.AdvancedEditOK = false;

  if (!InitEditorShell())
    return;

  // initialise the ok and cancel buttons
  doSetOKCancel(onOK, onCancel);

  // Element to edit is passed in
  element = window.arguments[1];
  if (!element || element == undefined) {
    dump("Advanced Edit: Element to edit not supplied\n");
    window.close();  
  }

  // place the tag name in the header
  var tagLabel = document.getElementById("tagLabel");
  tagLabel.setAttribute("value", ("<" + element.localName + ">"));

  // Create dialog object to store controls for easy access
  dialog                            = {};
  dialog.AddHTMLAttributeNameInput  = document.getElementById("AddHTMLAttributeNameInput");
  dialog.AddHTMLAttributeValueInput = document.getElementById("AddHTMLAttributeValueInput");
  dialog.AddHTMLAttribute           = document.getElementById("AddHTMLAttribute");
  dialog.AddCSSAttributeNameInput   = document.getElementById("AddCSSAttributeNameInput");
  dialog.AddCSSAttributeValueInput  = document.getElementById("AddCSSAttributeValueInput");
  dialog.AddCSSAttribute            = document.getElementById("AddCSSAttribute");
  dialog.AddJSEAttributeNameInput   = document.getElementById("AddJSEAttributeNameInput");
  dialog.AddJSEAttributeValueInput  = document.getElementById("AddJSEAttributeValueInput");
  dialog.AddJSEAttribute            = document.getElementById("AddJSEAttribute");

  // build the attribute trees
  BuildHTMLAttributeTable();
  BuildCSSAttributeTable();
  BuildJSEAttributeTable();
 
  // size the dialog properly
  window.sizeToContent();

  SetWindowLocation();
}

/**
 * function   : bool onOK ( void );
 * parameters : none
 * returns    : boolean true to close the window
 * desc.      : event handler for ok button
 **/
function onOK()
{
  UpdateObject(); // call UpdateObject fn to update element in document
  window.opener.AdvancedEditOK = true;
  window.opener.globalElement = element;

  SaveWindowLocation();

  return true; // do close the window
}

/**
 * function   : void UpdateObject ( void );
 * parameters : none
 * returns    : none
 * desc.      : Updates the copy of the page object with the data set in this dialog.
 **/
function UpdateObject()
{
    UpdateHTMLAttributes();
    UpdateCSSAttributes();
    UpdateJSEAttributes();
}

/**
 * function   : bool CheckAttributeNameSimilarity ( string attName, array attArray );
 * parameters : attribute to look for, array of current attributes
 * returns    : false if attribute already exists, true if it does not
 * desc.      : checks to see if any other attributes by the same name as the arg supplied
 *              already exist.
 **/
function CheckAttributeNameSimilarity(attName, attArray)
{
  for(var i = 0; i < attArray.length; i++)
  {
    if(attName.toLowerCase() == attArray[i].toLowerCase()) 
      return false;
  }
  return true;
}

/**
 * function   : bool CheckAttributeNotRemoved ( string attName, array attArray );
 * parameters : attribute to look for, array of deleted attributes
 * returns    : false if attribute already exists, true if it does not
 * desc.      : check to see if the attribute is in the array marked for removal 
 *              before updating the final object
 **/
function CheckAttributeNotRemoved( attName, attArray )
{
  for( var i = 0; i < attArray.length; i++ ) 
  {
    if(attName.toLowerCase() == attArray[i].toLowerCase()) 
      return false;
  }
  return true;
}

/**
 * function   : void doRemoveAttribute( DOMElement which);
 * parameters : DOMElement that was context-clicked.
 * returns    : nothing
 * desc.      : removes an attribute or attributes from the tree
 **/
function RemoveAttribute( treeId )
{
  var tree = document.getElementById(treeId);
  if (!tree) return;
  
  var kids = tree.lastChild;  // treechildren element of tree
  var newIndex = tree.selectedIndex;

  // We only allow 1 selected item
  if (tree.selectedItems.length)
  {
    var item = tree.selectedItems[0];
    // Name is the value of the treecell
    var attr = TrimString(item.firstChild.firstChild.getAttribute("value"));

    // remove the item from the attribute arrary
    switch ( tree.id ) {
      case "HTMLATree":
        HTMLRAttrs[HTMLRAttrs.length] = attr;
        if (newIndex >= (HTMLAttrs.length-1))
          newIndex--;
        RemoveNameFromAttArray(attr, HTMLAttrs);
        break;
      case "CSSATree":   
        // We write a completely new "style" string, so we don't need "remove" array
        //CSSRAttrs[CSSRAttrs.length] = attr;
        if (newIndex >= (CSSAttrs.length-1))
          newIndex--;
        RemoveNameFromAttArray(attr, CSSAttrs);
        break;
      case "JSEATree":
        JSERAttrs[JSERAttrs.length] = attr;
        if (newIndex >= (JSEAttrs.length-1))
          newIndex--;
        RemoveNameFromAttArray(attr, JSEAttrs);
        break;      
      default: break;
    }

    // Remove the item from the tree
    kids.removeChild (item);

    // Reselect an item
    tree.selectedIndex = newIndex;
    SelectTreeItem(tree);
  }
}
function RemoveNameFromAttArray(attName, attArray)
{
  for (var i=0; i < attArray.length; i++)
  {
    if(attName.toLowerCase() == attArray[i].toLowerCase()) 
    {
      // Remove 1 array item
      attArray.splice(i,1);
      break; 
    }
  }
}

// NOT USED
/*
function doSelect(e)
{
  if ( TEXT_WIDGETS_DONT_SUCK && PERFORMANCE_BOOSTS ) {
    var cell  = e.target.parentNode.lastChild;
    var input = cell.firstChild;

    var selitems = document.getElementsByAttribute("class","FocusSelected");
    for ( var i = 0; i < selitems.length; i++ )
    {
      if ( selitems[i].nodeName == "input" ) {
        selitems[i].removeAttribute("class","FocusSelected");
        selitems[i].setAttribute("class","AttributesCell");
      } else if ( selitems[i].nodeName == "treecell" )
        selitems[i].removeAttribute("class","FocusSelected");
    }
  
    cell.setAttribute("class","FocusSelected");
    input.setAttribute("class","FocusSelected");
    SetTextfieldFocus(input);
  }
}
*/

// adds a generalised treeitem.
function AddTreeItem ( name, value, treekidsId, attArray, valueCaseFunc )
{
  attArray[attArray.length] = name;
  var treekids    = document.getElementById ( treekidsId );
  var treeitem    = document.createElementNS ( XUL_NS, "treeitem" );
  var treerow     = document.createElementNS ( XUL_NS, "treerow" );
  var attrcell    = document.createElementNS ( XUL_NS, "treecell" );
  attrcell.setAttribute( "class", "propertylist" );
  attrcell.setAttribute( "value", name );
  // Modify treerow selection to better show focus in textfield
  treeitem.setAttribute( "class", "ae-selection");

  treerow.appendChild ( attrcell );
  
  if ( !valueCaseFunc ) {
    // no handling function provided, create default cell.
    var valCell = CreateCellWithField ( name, value );
    if (!valCell) return null;
    treerow.appendChild ( valCell );
  } else 
    valueCaseFunc();  // run user specified function for adding content
  
  treeitem.appendChild ( treerow );
  treekids.appendChild ( treeitem );
  return treeitem;
}

// creates a generic treecell with field inside.
// optional parameters for initial values.
function CreateCellWithField( name, value )
{
  var valCell     = document.createElementNS ( XUL_NS, "treecell" );
  if (!valCell) return null;
  valCell.setAttribute ( "class", "value propertylist" );
  valCell.setAttribute ( "allowevents", "true" );
  var valField    = document.createElementNS ( XUL_NS, "textfield" );
  if ( name  ) valField.setAttribute ( "id", name );
  if (!valField) return null;
  if ( value ) valField.setAttribute ( "value", value );
  valField.setAttribute ( "flex", "1" );
  valField.setAttribute ( "class", "plain" );
  valField.setAttribute ( "onfocus", "SelectItemWithTextfield(\""+name+"\")");
  valField.setAttribute ( "allowevents", "true");
  valCell.appendChild ( valField );
  return valCell;
}

function SelectItemWithTextfield(id)
{
  var textfield = document.getElementById(id);
  if (textfield)
  {
    var treeItem = textfield.parentNode.parentNode.parentNode;
    if (treeItem)
    {
      // Prevent SelectTreeItem() from setting selection to entire textfield
      gSelecting = true;
      treeItem.parentNode.parentNode.selectItem(treeItem);
      gSelecting = false;
    }
  }
}

// When a "name" treecell is selected, shift focus to the textfield
function SelectTreeItem(tree)
{
  // Prevent infinite loop -- SetTextfieldFocusById triggers recursive call
  if (gSelecting) return;
  gSelecting = true;  
  if (tree && tree.selectedItems && tree.selectedItems.length)
  {
    // 2nd cell (value column) contains the textfield
    var textfieldCell = tree.selectedItems[0].firstChild.firstChild.nextSibling;
    if (textfieldCell)
    {
      // Select its contents and set focus
      SetTextfieldFocusById(textfieldCell.firstChild.id);
    }
  }
  gSelecting = false;
}

// todo: implement attribute parsing, e.g. colorpicker appending, etc.
function AttributeParser( name, value )
{
  
}

