/**
 *  object to control the desktop
 *
 *  @author   Tobias Hettinger
 *  @version  $Id: control.js,v 1.38 2009/05/15 11:54:35 tobias Exp $
 */
 
 
/**
 *  constructor
 *
 *  @param string name     name of the desktop control class
 *  @param object desktop  desktop object to control
 */
var WATDesktopControl = function(name, desktop)
{
  //  set the member variables
  this.name = name;
  this.desktop = desktop;
}


//=====================================================================================================================
//  content loader
//=====================================================================================================================

/**
 *  function to control the sheet content request
 *
 *  @param int requestId  id of the content request
 */
WATDesktopControl.prototype.__AjaxResponse = function(requestId)
{
  var xmlHttpRequest = WATAjaxRequestData[requestId][0];
  var sheet = WATAjaxRequestData[requestId][2];
 
  //  check if the request was finished
  if (xmlHttpRequest.readyState == 4)
  {
    //  check if the request succeeded
    if (xmlHttpRequest.status == 200)
    {
      var ajaxResponse = xmlHttpRequest.responseXML.documentElement;
      if (ajaxResponse)
      {
        //  parse the ajax response
        this.ParseXML(ajaxResponse);
      }
      else
      {
        //  there is no valid XML
        alert(xmlHttpRequest.responseText);
      }
    }
    else
    {
      //  there was an error
      alert('the request failed with error \n\n' + xmlHttpRequest.statusText + ' (' + xmlHttpRequest.status + ')');
    }
    
    //  release the request object (this has to be done manually)
    WATAjaxRequestData[requestId][1] = false;
  }
}

/**
 *  function to require the content for the passed sheet
 *
 *  @param object sheet  sheet for which the content is required
 */
WATDesktopControl.prototype.RequireSheetContent = function(sheet)
{
  if (sheet.requestSource != null && sheet.requestParameters != null)
  {
    //  start the content request
    watAjaxSendRequest(sheet.requestSource, sheet.requestParameters, WAT_AJAX_REQUEST_POST,
                       this.name + '.__AjaxResponse', sheet);
  }
}


//=====================================================================================================================
//  XML parser
//=====================================================================================================================

/**
 *  function to parse a frame XML response. The frame parser is not integrated into the main
 *  XML parse function in order to support sub-frames which are located on sheets
 *
 *  @param object xml          XML frame node
 *  @param object parentSheet  sheet which contains the frame or null if the frame is directly located on the desktop
 */
WATDesktopControl.prototype.__ParseFrameXML = function(xml, parentSheet)
{
  //  get the name of the frame
  var frameName = xml.getAttribute('n');
  if (frameName)
  {
    //  get the frame object
    var frame = this.desktop.GetFrame(frameName);
    if (frame)
    {
      var autoScroll = xml.getAttribute('as');  //  result is null (!= 0) if the value is not set
      if (autoScroll == 0) frame.DisableAutoScroll();
      if (autoScroll == 1) frame.EnableAutoScroll(); 
    
      //  get the parent nodes of the frame
      var frameNode = xml.firstChild;
      while(frameNode)
      {
        switch(frameNode.nodeName)
        {
          //  a sheet definition has been sent
          case 'ds' :
            var sheetName = frameNode.getAttribute('n');
            var sheetCaption = frameNode.getAttribute('c');
            var contentHash = frameNode.getAttribute('hash');
            if (sheetName)
            {
              //  get the sheet object
              var sheet = frame.GetSheet(sheetName);
              
              //  there is no sheet object yet, create a new one
              if (sheet == null) sheet = frame.AddSheet(sheetName, false, sheetCaption, null, contentHash);              
              if (sheet != null)
              {
                //  get the sheet attributes
                var showSheet = frameNode.getAttribute('s');
                showSheet = (showSheet == '1' ? true : false);
                
                var sheetFlags = frameNode.getAttribute('f');
                if (sheetFlags) sheet.flags = parseInt(sheetFlags);

                //  get the grid
                var columns = frameNode.getAttribute('cols');
                if (columns && parseInt(columns) > 0)
                {
                  var grid = new WATDesktopGrid();
                  grid.colCount = parseInt(columns);
                  frame.AddGrid(grid);
                  sheet.SetGrid(grid);
                }

                //  set the contentInitialized flag but do not remove it if the 'ci' attribute is not set
                var contentInitialized = frameNode.getAttribute('ci');
                if (contentInitialized && contentInitialized == '1') sheet.contentInitialized = true;
                
                var sheetNode = frameNode.firstChild;
                var content = null;
                var contentSet = false;
                
                while(sheetNode)
                {
                  switch(sheetNode.nodeName)
                  {
                                
            //  form configuration
            case 'fc' :
              if (!contentSet && content != null) { sheet.SetContent(content, contentHash); contentSet = true; }
                
              if (this.desktop.formManager)
                this.desktop.formManager.ParseXML(sheetNode, frameName, sheetName);
              break; 
                  
                    //  the sheet should be shown
                    case 'show' :
                      showSheet = true;
                      break;
                  
                    //  the content requires a special java script
                    case 'script' :
                      var scripts = document.getElementsByTagName('script');
                      var scriptUrl = sheetNode.firstChild.data;
                      
                      //  check if the script has not yet been loaded
                      var found = false;
                      for (var i in scripts)
                        if (scripts[i].src == scriptUrl) found = true;
                        
                      if (!found)
                      {
                        //  the script was not loaded yet
                        var scriptElement = document.createElement('script');
                        scriptElement.type = 'text/javascript';
                        scriptElement.src = scriptUrl;
                        document.getElementsByTagName('head')[0].appendChild(scriptElement);
                      }
                      break;
                      
                    //  the content requires a special css file
                    case 'style' :
                      var styles = document.getElementsByTagName('link');
                      var styleUrl = sheetNode.firstChild.data;
                      
                      //  check if the css file has not yet been loaded
                      var found = false;
                      for (var i in styles)
                        if (styles[i].href == styleUrl) found = true;

                      if (!found)
                      {
                        //  the css file was not loaded yet
                        var styleElement = document.createElement('link');
                        styleElement.rel = 'stylesheet';
                        styleElement.type = 'text/css';
                        styleElement.href = styleUrl;
                        styleElement.media = 'screen,print';
                        document.getElementsByTagName('head')[0].appendChild(styleElement); 
                      }
                      break;
                      
                    //  a javascript variable is to be set
                    case 'var' :
                      var varName = sheetNode.getAttribute('n');
                      var varValue = (sheetNode.firstChild != null) ? sheetNode.firstChild.data : null;
                      
                      //  set the variable
                      if (varValue)
                      {
                        varValue = watDivDecode(varValue);
                        eval(varName + '=' + varValue + ';');
                      }
                      break;
                      
                    //  a javascript command is to be executed
                    case 'js' :
                      var jsValue = (sheetNode.firstChild != null) ? sheetNode.firstChild.data : null;
                      if (jsValue)
                      {                      
                        //  set the variable
                        jsValue = watDivDecode(jsValue);
                        eval(jsValue + ';');
                      }
                      break;
                  
                    //  new content has been sent
                    case 'c' :
                      if (!contentSet)
                      {
                      if (sheetNode.firstChild)
                        if (content == null) content = sheetNode.firstChild.data;
                          else content += sheetNode.firstChild.data;
                      }
                      else alert('the content has already been set');
                      break;
                      
                    case 'data' :
                      var dataKey = sheetNode.getAttribute('key');
                      if (dataKey && sheetNode.firstChild)
                        sheet.SetData(dataKey, sheetNode.firstChild.data);
                      break;
                      
                    //  a new gadget has been sent
                    case 'gd' :
                      //  get the required attributes
                      var key = sheetNode.getAttribute('k');
                      //  create a new desktop element if the required attributes are set
                      if (key)
                      { 
                        //  get the optional attributes
                        var top = sheetNode.getAttribute('t');
                        var left = sheetNode.getAttribute('l');
                        var width = sheetNode.getAttribute('w');
                        var height = sheetNode.getAttribute('h');
                        var column = sheetNode.getAttribute('c');
                        var colSpan = sheetNode.getAttribute('cs');
                        var className = sheetNode.getAttribute('class');
                        var ajaxHandler = sheetNode.getAttribute('ah');
                        var modulePrefix = sheetNode.getAttribute('mp');
                        var skinPrefix = sheetNode.getAttribute('sp');
                        var autoUpdate = sheetNode.getAttribute('au');
                        var movable = sheetNode.getAttribute('m');
                        var sizableWidth = sheetNode.getAttribute('sw');
                        var sizableHeight = sheetNode.getAttribute('sh');
                        var autoUpdateCommand = watDivDecode(sheetNode.getAttribute('auc'));
                        var elementContent = null;

                        //  check the parameters
                        if (!top || top < 0) top = 0;
                        if (!left || left < 0) left = 0;
                        if (!width || width < 0) width = -1;
                        if (!height || height < 0) height = -1;
                        
                        //  set the grid
                        if (sheet.grid && column != null && colSpan && colSpan > 0)
                        {
                          if (sheet.grid && sheet.grid.width == null)
                            this.desktop.UpdateFrameset();
                          
                          left = column * sheet.grid.colWidth;
                          width = colSpan * sheet.grid.colWidth;
                        }
                        
                        //  get the element data
                        var deNode = sheetNode.firstChild;
                        while(deNode)
                        {
                          switch(deNode.nodeName)
                          {
                            //  new content has been sent
                            case 'c' :
                              if (deNode.firstChild)
                                if (elementContent == null) elementContent = deNode.firstChild.data;
                                  else elementContent += deNode.firstChild.data;
                              break;
                          }
                        
                          //  get the next element data node
                          deNode = deNode.nextSibling;
                        }
                        
                        //  register the desktop element
                        var gadget = this.desktop.CreateGadget(key, sheet, className, elementContent,
                                                               top, left, width, height);
                        gadget.ajaxHandler = ajaxHandler;
                        gadget.modulePrefix = modulePrefix;
                        gadget.skinPrefix = skinPrefix;
                        if (movable) gadget.movable = true;
                        if (sizableWidth) gadget.sizableWidth = true;
                        if (sizableHeight) gadget.sizableHeight = true;
                        
                        if (autoUpdate && autoUpdateCommand)
                        {
                          gadget.autoUpdate = autoUpdate;
                          gadget.autoUpdateCommand = autoUpdateCommand;
                          setTimeout(autoUpdateCommand, autoUpdate);
                        }
                        
                        gadget.Create();
                      }
                      break;
                      
                    case 'gdinit' :
                      //  get the required attributes
                      var key = sheetNode.getAttribute('k');
                      var initFunction = sheetNode.getAttribute('f');
                      var command = (sheetNode.firstChild != null) ? sheetNode.firstChild.data : null;
                      if (key && initFunction && command) watExecFunc(initFunction, watDivDecode(command), 50);
                      break;
                      
                    //  clear all gadgets
                    case 'gdclall' :
                      desktop.RemoveGadget(null);
                      break;
                      
                    case 'gdresize' :
                      desktop.UpdateFrameset();
                      desktop.ResizeGadgets(sheet);
                      break;
                  }

                  //  get the next sheet child node
                  sheetNode = sheetNode.nextSibling;
                }

                //  set the content is there is one (set the hash value or null if there is no hash value)
                if (!contentSet && content != null) sheet.SetContent(content, contentHash);
                //  show the sheet
                if (showSheet) frame.ShowSheet(sheetName);
              }
            }
            break;
        }
        
        //  get the next part of the frame node
        frameNode = frameNode.nextSibling;
      }
    }
  }
}

/**
 *  function to parse a context menu XML response. The menu parser is not integrated into the main
 *  XML parse function in order to support sub-menus for the main menu
 *
 *  @param object xml         XML context menu node
 *  @param object parentMenu  parent menu if a parent menu is avaliable or null if there is no parent menu
 */
WATDesktopControl.prototype.__ParseContextMenuXML = function(xml, parentMenu)
{
  var contextMenuName = xml.getAttribute('n');
  if (contextMenuName)
  {
    //  try to get the context menu
    var contextMenu = this.desktop.GetContextMenu(contextMenuName);
    if (!contextMenu)
    {
      //  the context menu is not available, try to create a new one
      var imgBaseUrl = xml.getAttribute('img');
      var baseClassName = xml.getAttribute('class');
      if (imgBaseUrl && baseClassName)
        contextMenu = this.desktop.CreateContextMenu(contextMenuName, imgBaseUrl, baseClassName, 200);
    }
    
    //  parse the XML if the context menu exists or could have been created
    if (contextMenu)
    {
      var menuNode = xml.firstChild;
      while(menuNode)
      {
        switch(menuNode.nodeName)
        {
          //  clear the existing menu items
          case 'cl' :
            contextMenu.ClearItems();
            break;
        
          //  a new menu item has been sent
          case 'i' :
            var name = menuNode.getAttribute('n');
            var href = menuNode.getAttribute('href');
            var icon = menuNode.getAttribute('icon');
            var caption = menuNode.firstChild ? menuNode.firstChild.data : null;

            if (name && href && caption)
              contextMenu.AddItem(name, caption, icon, href, null);
            break;
        
          //  show the context menu
          case 'show' :
            contextMenu.Show();
            break;
        }
      
        //  get the next node
        menuNode = menuNode.nextSibling;
      }
    }
  }
}

WATDesktopControl.prototype.__ParseLightboxXML = function(xml)
{
  var lightboxName = xml.getAttribute('n');
  if (lightboxName)
  {
    //  try to get the lightbox, create a new one if the lightbox does not exist
    var lightbox = this.desktop.GetLightbox(lightboxName);
    if (!lightbox) lightbox = this.desktop.CreateLightbox(lightboxName);

    if (lightbox)
    {
      var node = xml.firstChild;
      while(node)
      {
        switch(node.nodeName)
        {
          case 'bg' :
            var className = node.getAttribute('class');
            if (lightbox.background == null) lightbox.CreateBackground(999, className);
            break;
            
          case 'sbg' :
            lightbox.ShowBackground(50, 350);
            break;
            
          case 'hbg' :
            lightbox.HideBackground(350);
            break;
            
          case 'div' :
            var className = node.getAttribute('class');
            var width = node.getAttribute('w');
            var height = node.getAttribute('h');
            var lightboxContent = null;
            
            //  get the content of the div
            var divNode = node.firstChild;
            while(divNode)
            {
              switch(divNode.nodeName)
              {
                //  new content has been sent
                case 'c' :
                  if (divNode.firstChild)
                    if (lightboxContent == null) lightboxContent = divNode.firstChild.data;
                      else lightboxContent += divNode.firstChild.data;
                  break; 
              }
            
              //  get the next element data node
              divNode = divNode.nextSibling;
            }
            
            lightbox.CreateDiv(-1, -1, width, height, 2000, className, lightboxContent, 0, 0, 0, 0);
            break;
            
          //  form configuration
          case 'fc' :                   
            if (this.desktop.formManager)
              this.desktop.formManager.ParseXML(node, 'lightbox', lightboxName);
            break;
            
          case 'sdiv' :
            lightbox.ShowDiv(100, 350);
            break;
            
          case 'hdiv' :
            lightbox.HideDiv(0, 350);
            break;
        }
        
        //  get the next node
        node = node.nextSibling;
      }
    }
  }
}

/**
 *  function to parse an XML response
 *
 *  @param object xml                   node of an XML response
 *  @param string responseFunctionName  name of the function which should be called as request handler
 *                                      when the parser function sends an ajax request
 */
WATDesktopControl.prototype.ParseXML = function(xml, responseFunctionName)
{
  //  get the response or error elements
  var node = xml.firstChild;
  while(node)
  {
    switch(node.nodeName)
    {
      //  desktop data has been sent
      case 'desktop' :
        //  parse the desktop data
        var desktop = node.firstChild;
        while(desktop)
        {
          switch(desktop.nodeName)
          {
            //  a frame has been sent
            case 'df' :
              //  parse the frame structure
              this.__ParseFrameXML(desktop, null);
              break;
              
            //  a context menu has been sent
            case 'cm' :
              //  parse the context menu structure
              this.__ParseContextMenuXML(desktop, null);
              break;
              
            //  a lightbox has been sent
            case 'lb' :
              this.__ParseLightboxXML(desktop);
              break;
              
            //  the request requires a special java script
            case 'script' :
              var scripts = document.getElementsByTagName('script');
              var scriptUrl = desktop.firstChild.data;

              //  check if the script has not yet been loaded
              var found = false;
              for (var i in scripts)
                if (scripts[i].src == scriptUrl) found = true;
                
              if (!found)
              {
                //  the script was not loaded yet
                var scriptElement = document.createElement('script');
                scriptElement.type = 'text/javascript';
                scriptElement.src = scriptUrl;
                document.getElementsByTagName('head')[0].appendChild(scriptElement);
              }
              break;
          
            //  the content requires a special css file
            case 'style' :
              var styles = document.getElementsByTagName('link');
              var styleUrl = desktop.firstChild.data;
              
              //  check if the css file has not yet been loaded
              var found = false;
              for (var i in styles)
                if (styles[i].href == styleUrl) found = true;

              if (!found)
              {
                //  the css file was not loaded yet
                var styleElement = document.createElement('link');
                styleElement.rel = 'stylesheet';
                styleElement.type = 'text/css';
                styleElement.href = styleUrl;
                styleElement.media = 'screen,print';
                document.getElementsByTagName('head')[0].appendChild(styleElement); 
              }
              break;
          
            //  a form was sent
            case 'form' :
              //  initialize the data that is required for splitted transfer of the HTML code
              var htmlCode = '';
              var htmlData = null;
              var formKey = desktop.getAttribute('key');
              var caption = desktop.getAttribute('caption');
              var buttons = null;
              
              //  check the attributes
              if (!formKey) formKey = 'default';

              //  get the form data
              var formData = desktop.firstChild;
              while(formData)
              {
                switch(formData.nodeName)
                {
                  //  the html code to show was sent
                  case 'html' :
                    //  get the data parameter (show a form to add a new item if there is none)
                    htmlData = formData.getAttribute('data');
                    //  get the code
                    htmlCode = htmlCode + formData.firstChild.data;
                    break;
                    
                  //  a button has been sent
                  case 'button' :
                    //  get the attributes
                    var buttonCaption = formData.getAttribute('caption');
                    var buttonOnClick = formData.getAttribute('onclick');
                    
                    //  register the button
                    if (buttonCaption && buttonOnClick)
                    {
                      if (!buttons) buttons = new Array();
                      var button = new Array();
                      button['onclick'] = buttonOnClick;
                      button['caption'] = buttonCaption;
                      buttons.push(button);
                    }
                    break;
                }
                
                //  get the next part of the form data
                formData = formData.nextSibling;
              }
              
              //  show the form if there is some HTML code
              if (htmlCode) this.desktop.CreateForm(formKey, 'ajax_form', caption, htmlCode, buttons);
              break;
              
            //  a form should be closed
            case 'cf' :
              //  initialize the variables
              var formKey = desktop.getAttribute('key');
              if (!formKey) formKey = 'default';
              //  close the form
              this.desktop.CloseForm(formKey);
              break;
              
            //  a link is to be modified
            case 'ml' :
              //  get the attributes
              var id = desktop.getAttribute('id');
              var href = desktop.getAttribute('href');
              var caption = desktop.firstChild ? desktop.firstChild.data : null;
              //  try to modify the link
              if (id && href && caption)
              {
                var linkElement = document.getElementById(id);
                if (linkElement)
                {
                  //  modify the link
                  linkElement.innerHTML = caption;
                  linkElement.href = href;
                }
              }
              break;
              
            //  a javascript command is to be executed
            case 'js' :
              var jsValue = (desktop.firstChild != null) ? desktop.firstChild.data : null;
              if (jsValue)
              {
                //  set the variable
                jsValue = watDivDecode(jsValue);
                eval(jsValue + ';');
              }
              break;
              
            //  the content of a div should be set/replaced
            case 'div' :
              var divContent = '';
              var divId = desktop.getAttribute('id');
              if (divId)
              {
                //  get the content for the div
                var div = desktop.firstChild;
                while(div)
                {
                  switch(div.nodeName)
                  {
                    //  the next part of the content has been sent
                    case 'c' :
                      if (div.firstChild) divContent += div.firstChild.data;
                      break;
                  }
                  
                  //  get the next node
                  div = div.nextSibling;
                }
                
                //  update the content of the div
                watDivContent(divId, divContent);
              }
              break;
              
            //  the user has to confirm a question
            case 'confirm' :
              //  get the question
              var question = desktop.getElementsByTagName('question');
              if (question)
              {
                //  get the answer
                var answer = confirm(question.item(0).firstChild.data);
                //  react on the answer
                var answerNode = node.getElementsByTagName(answer ? 'yes' : 'cancel');
                if (answerNode.item(0))
                {
                  //  show a message if the answer element contains data
                  if (answerNode.item(0).firstChild && answerNode.item(0).firstChild.data)
                    alert(answerNode.item(0).firstChild.data);
                  //  get the attributes
                  var url = answerNode.item(0).getAttribute('url');
                  var parameters = answerNode.item(0).getAttribute('parameters');
                  //  start an ajax request
                  if (url && parameters)
                  {
                    //  prepare the parameters
                    parameters = parameters.replace(/§!and!§/g, '&');
                    //  start the request
                    watAjaxSendRequest(url, 'ax=1&'+parameters, WAT_AJAX_REQUEST_POST, responseFunctionName);
                  }
                }
              }
              break;
              
            //  an input error has been detected
            case 'inputError' :
            case 'ierr' :
              var id = desktop.getAttribute('id');
              var message = (desktop.firstChild && desktop.firstChild.data) ? desktop.firstChild.data : null;
              if (id)
              {
                //  get the input field
                var field = document.getElementById(id);
                if (field)
                {
                  field.style.borderColor = '#DD0000';
                  field.style.borderWidth = '2px';
                }
                
                //  enable the error balloon
                this.desktop.EnableErrorBalloon(id, message);
              }
              break;
              
            //  clear an input error notice
            case 'inputOk' :
            case 'iok' :
              var id = desktop.getAttribute('id');
              if (id)
              {
                //  get the field
                var field = document.getElementById(id);
                if (field)
                {
                  field.style.borderColor = '#000000';
                  field.style.borderWidth = '1px';
                }
              }
              break;
             
            //  an XML structure for a select box should be parsed
            case 'select' :
              //  get the combo box
              var name = desktop.getAttribute('n');
              var selectBox = null;
              eval('if (typeof(' + name + ') != "undefined") selectBox = ' + name + ';');
              
              //  now the selectBox variable contains the reference to the selectBox object or null 
              //  if there is no object with the specified name
              if (selectBox) selectBox.ParseXML(desktop); 
              break;
              
            //  an XML structure for a combo box should be parsed
            case 'combo' :
              //  get the combo box
              var name = desktop.getAttribute('n');
              var comboBox = null;
              eval('if (typeof(' + name + ') != "undefined") comboBox = ' + name + ';');
              
              //  now the comboBox variable contains the reference to the comboBox object or null 
              //  if there is no object with the specified name
              if (comboBox && comboBox.selectBox) comboBox.ParseXML(desktop);                
              break;
              
                      
            //  clear the gadget with the specified key
            case 'gdcl' :
              //  get the required attributes
              var key = desktop.getAttribute('k');
              //  remove the gadget
              if (key) this.desktop.RemoveGadget(key);
              break;
          }
        
          //  get the next child
          desktop = desktop.nextSibling;
        }
        break;
    
      //  hide the div with the specified key
      case 'hideDiv' :
        var id = node.getAttribute('id');
        if (id && watDivExists(id)) watDivRemove(id);
        break;
        
      //  an error message has been sent
      case 'error' :
        //  show an error message
        var message = node.getElementsByTagName('message');
        if (message && message.item(0) && message.item(0).firstChild) alert(watDivDecode(message.item(0).firstChild.data));
          else alert('there was an error without a message');
        break;
    }
    
    //  get the next node
    node = node.nextSibling;
  }
}
