/**
 *  object to control the objects on the current document
 * 
 *  @author   Tobias Hettinger
 *  @version  $Id: desktop.js,v 1.38 2009/05/15 11:54:35 tobias Exp $
 */

 
/**
 *  constructor
 *
 *  @param string name  name of the desktop manager
 */
var WATDesktop = function(name)
{
  //  set the member variables
  this.name = name;
  this.gadgets = new Array();
  this.forms = new Array();
  this.designs = new Array();
  this.frames = new Array();
  this.contextMenus = new Array();
  this.lightboxes = new Array();
  this.errorBalloon = null;
  this.errorBalloonEffects = null;
  this.gadgetControlAjaxHandler = null;
  this.gadgetControlSessionParam = null;
  this.formManager = null;
  
  //  create the div for the screen saver
  this.screenDiv = document.createElement('div');
  this.screenDiv.id = name + 'screen';
  this.screenDiv.style.backgroundColor = '#000000';
  this.screenDiv.style.position = 'absolute';
  this.screenDiv.style.display = 'none';
  this.screenDiv.style.top = '0px';
  this.screenDiv.style.left = '0px';
  this.screenDiv.style.zIndex = 4000;
  
  //  initialize screensaver data
  this.screenMouseMove = 0;
  this.screenDivControl = null;
  this.screenDark = false;
  
  //  register the divEffects modification event
  var obj = this;
  function __OnGadgetModify(divEffects, flags)
  {
    if (flags == 1)
    {
      var resizeSheet = null;
      for (var i in obj.gadgets)
        if (obj.gadgets[i] && obj.gadgets[i].divEffects && obj.gadgets[i].divEffects == divEffects)
          resizeSheet = obj.gadgets[i].sheet;
      
      if (resizeSheet && resizeSheet.grid) obj.ResizeGadgets(resizeSheet);

      for (var i in obj.gadgets)
        if (obj.gadgets[i] && obj.gadgets[i].divEffects && obj.gadgets[i].divEffects == divEffects)
          obj.gadgets[i].Resize(true);
    }
    else
    {
      for (var i in obj.gadgets)
        if (obj.gadgets[i] && obj.gadgets[i].divEffects && obj.gadgets[i].divEffects == divEffects)
          obj.gadgets[i].Resize(false);
    }
  }

  WATOnDivEffectsModify.AddHandler(__OnGadgetModify);
}


//=====================================================================================================================
//  screen saver
//=====================================================================================================================

/**
 *  function which is called periodically in order to check if the screensaver has to be enabled
 */
WATDesktop.prototype.__ScreenSaver = function()
{
  var dayObj = new Date();
  var now = Math.floor(dayObj.getTime() / 1000);

  //  enable the screen saver
  if (this.screenMouseMove > 0 && (now - this.screenMouseMove > 600) && !this.screenDark)
  {
    this.screenDivControl.FadeIn(95, 5000);
    this.screenDark = true;
  }
  
  //  call the function periodically
  setTimeout(this.name + '.__ScreenSaver()', 5000);
}

/**
 *  function to enable the screen saver
 */
WATDesktop.prototype.EnableScreenSaver = function()
{
  //  enable the screensaver only once
  if (this.screenDivControl == null)
  {
    //  create the objects
    document.body.appendChild(this.screenDiv);
    this.screenDivControl = new WATDivEffects(this.name + '.screenDivControl', this.name + 'screen');
  
    //  initialize the screen saver
    var dayObj = new Date();
    this.screenMouseMove = Math.floor(dayObj.getTime() / 1000);
    
    obj = this;
    function __MouseMove()
    {
      var dayObj = new Date();
      obj.screenMouseMove = Math.floor(dayObj.getTime() / 1000);
      
      if (obj.screenDark)
      {
        obj.screenDivControl.FadeOut(0, 1);
        obj.screenDark = false;
      }
    }
   
    //  register the event handlers
    if (WATBrowserInfo.IsIE)
    {  
      //  ... for Internet Explorer
      document.attachEvent('onmousemove', __MouseMove);
    }
    else
    {
      //  ... for other browsers
      document.addEventListener('mousemove', __MouseMove, true);
    }
    
    //  start the screen saver
    this.__ScreenSaver();
  }
}


//=====================================================================================================================
//  design management
//=====================================================================================================================

/**
 *  function to register a desktop design
 *
 *  @param string baseClassName    name of the used base css class
 *  @param string formImgBasePath  full url to the form images of the form with the passed css class
 */
WATDesktop.prototype.RegisterDesign = function(baseClassName, formImgBasePath)
{
  //  create a new design entry
  var design = new Array();
  design['formImgBasePath'] = formImgBasePath;
  
  //  register the new design
  this.designs[baseClassName] = design;
}


//=====================================================================================================================
//  frame management
//=====================================================================================================================

/**
 *  function to add a new frame
 *
 *  @param string name          name of the frame which is used to access the frame from the application
 *  @param string cssClassName  name of the css class which is used for the frame
 *  @param int    align         alignment code of the frame (see the description of the frame object)
 *  @param int    top           top position of the frame in pixel (it depends on the alignment mode if the
 *                              position (top,left,width,height) properties are used
 *  @param int    left          left position of the frame in pixel
 *  @param int    width         width of the frame in pixel
 *  @param int    height        height of the frame in pixel
 *  @param bool   visible       if true, the frame is visible, if false, the frame is not visible by default
 */
WATDesktop.prototype.AddFrame = function(name, cssClassName, align, top, left, width, height, visible)
{
  //  create a new frame definition
  var frame = new WATDesktopFrame(name, cssClassName, align, top, left, width, height, visible);  
  //  add the frame to the frames array of the desktop (order by index)
  this.frames.push(frame);
  
  //  return the created frame object
  return frame;
}

/**
 *  function to get the frame with the passed name
 *
 *  @param string name  name of the frame
 *
 *  @return object  the function returns the selected frame object or null if the frame has not been found
 */
WATDesktop.prototype.GetFrame = function(name)
{
  //  search the frame with the passed name
  for (var i in this.frames)
    if (this.frames[i].name == name) return this.frames[i];
    
  //  the frame has not been found
  return null;
}

/**
 *  function to update the frameset
 */
WATDesktop.prototype.UpdateFrameset = function()
{
  //  initialize the variables
  var usedTop = 0, usedLeft = 0, usedRight = 0, usedBottom = 0;
  var width = watGetWindowWidth();
  var height = watGetWindowHeight();
  var finish = false;

  //  update the background of the screen saver
  this.screenDiv.style.width = width + 'px';
  this.screenDiv.style.height = height + 'px';
  
  //  update the lightboxes
  for (var i in this.lightboxes)
    if (this.lightboxes[i].backgroundVisible || this.lightboxes[i].divVisible) this.lightboxes[i].Update();
  
  //  update the frames
  for (var i in this.frames)
  {
    //  get the frame
    var frame = this.frames[i];
  
    //  after the first 'middle'-frame has been created, no other frame can be placed
    if (!finish && frame.visible)
    {
      switch(frame.align)
      {
        //  absolute frame position
        case 0 :
          frame.divElement.style.top = frame.top + 'px';
          frame.divElement.style.left = frame.left + 'px';
          frame.divElement.style.width = frame.width + 'px';
          frame.divElement.style.height = frame.height + 'px';
          break;
          
        //  top aligned frame
        case 1 :
          frame.divElement.style.top = usedTop + 'px';
          frame.divElement.style.left = usedLeft + 'px';
          frame.divElement.style.height = frame.height + 'px';
          frame.divElement.style.width = (width - usedRight - usedLeft) + 'px';
          usedTop += frame.height;
          break;
          
        //  right aligned frame
        case 2 :
          frame.divElement.style.top = usedTop + 'px';
          frame.divElement.style.left = (width - frame.width) + 'px';
          frame.divElement.style.width = frame.width + 'px';
          frame.divElement.style.height = (height - usedTop - usedBottom) + 'px';
          usedRight += frame.width;
          break;
          
        //  left aligned frame
        case 3 :
          frame.divElement.style.top = usedTop + 'px';
          frame.divElement.style.left = usedLeft + 'px';
          frame.divElement.style.width = frame.width + 'px';
          frame.divElement.style.height = (height - usedTop - usedBottom) + 'px';
          usedLeft += frame.width;
          break;
          
        //  bottom aligned frame
        case 4 :
          frame.divElement.style.top = (height - usedBottom - frame.height) + 'px';
          frame.divElement.style.left = usedLeft + 'px';
          frame.divElement.style.width = (width - usedLeft - usedRight) + 'px';
          frame.divElement.style.height = frame.height + 'px';
          usedBottom += frame.height;
          break;
          
        //  middle frame
        case 5 :
          frame.divElement.style.top = usedTop + 'px';
          frame.divElement.style.left = usedLeft + 'px';
          frame.divElement.style.width = (width - usedLeft - usedRight) + 'px';
          frame.divElement.style.height = (height - usedTop - usedBottom) + 'px';
          
          frame.width = (width - usedLeft - usedRight);
          frame.height = (height - usedTop - usedBottom);
          
          //  finish after the middle frame has been shown
          finish = true;
          break;
      }
      
      //  resize the grids of the frame
      frame.ResizeGrids();
      if (frame.GetActiveSheet()) this.ResizeGadgets(frame.GetActiveSheet());
    }
    else
    {
      //  hide the frames that can not be shown
      if (frame.visible) frame.SetVisible(false);
    }
  }
}


//=====================================================================================================================
//  form manager
//=====================================================================================================================

/**
 *  function to create a form
 *
 *  @param string key            key of the form which is used to access the form (e.g. for closing it)
 *  @param string baseClassName  css class of the form
 *  @param string caption        caption of the form (simply a string with the name of the form)
 *  @param string content        content of the form (full html code to show)
 *  @param array  buttons        array of button definitions. The structure of the array is
 *                               - onclick - onclick handler of the button
 *                               - caption - caption of the button
 */
WATDesktop.prototype.CreateForm = function(key, baseClassName, caption, content, buttons)
{
  //  initialize the variables
  var form = null;
  var formFound = false;
  var i = 0;
  
  //  search if there is a usable form
  for (i in this.forms)
  {
    if (this.forms[i].key == key) formFound = true;
    if (form == null && this.forms[i].used == false)
      form = this.forms[i];
  }
  
  //  create a new form if no form is available
  if (form == null)
  {
    form = new WATDesktopForm(this, this.forms.length);
    this.forms.push(form);
  }
 
  //  create the form
  if (!formFound) form.CreateForm(key, baseClassName, caption, content, buttons);
  this.FormFocus(key);
}

/**
 *  function to close the form with the passed key
 *
 *  @param string key  key of the form to close
 */
WATDesktop.prototype.CloseForm = function(key)
{
  for (i in this.forms)
    if (this.forms[i].key == key && this.forms[i].used == true) this.forms[i].CloseForm();
}

/**
 *  function to set the focus to the form with the passed key
 *
 *  @param string key  key of the selected form
 */
WATDesktop.prototype.FormFocus = function(key)
{
  //  the indexes of the forms start with 800
  var index = 800;

  //  search the selected form and set a z-index of 999
  for (i in this.forms)
  {
    if (this.forms[i].key == key)
      this.forms[i].divElement.style.zIndex = 999;
    else
      this.forms[i].divElement.style.zIndex = index;
      
    index++;
  }
}


//=====================================================================================================================
//  context menu manager
//=====================================================================================================================

/**
 *  function to create a context menu
 *
 *  @param string name           instance name of the context menu object
 *  @param string imgBaseUrl     image base url with a path separator at the end
 *  @param string baseClassName  base class name of the context menu div. Since the classes of the "inner" elements
 *                               are fixed, the base class has to be used to choose a context menu style
 *  @param int    width          width of the context menu
 *
 *  @return class  the function returns the created context menu
 */
WATDesktop.prototype.CreateContextMenu = function(name, imgBaseUrl, baseClassName, width)
{
  //  create a new context menu
  var contextMenu = new WATContextMenu(this.name + ".contextMenus['" + name + "']", imgBaseUrl,
                                       baseClassName, width, name);
  //  register the new context menu
  this.contextMenus[name] = contextMenu;
  return contextMenu;
}

/**
 *  function to get the context menu with the passed name
 *
 *  @param string name  name of the required context menu
 *
 *  @return class  the function returns the context menu if it has been found or null if the context menu
 *                 has not been found
 */
WATDesktop.prototype.GetContextMenu = function(name)
{
  //  search the menu
  for (var i in this.contextMenus)
    if (i == name) return this.contextMenus[i];
  //  the menu has not been found
  return null;
}


//=====================================================================================================================
//  balloon manager
//=====================================================================================================================

/**
 *  function to set the error balloon for the desktop
 *
 *  @param object balloon  error balloon object
 */
WATDesktop.prototype.SetErrorBalloon = function(balloon)
{
  //  set the error balloon
  this.errorBalloon = balloon;
}

/**
 *  function to enable the error balloon
 */
WATDesktop.prototype.EnableErrorBalloon = function(fieldId, message)
{
  //  enable the balloon if the field id, the message and the balloon are available
  if (fieldId && message && this.errorBalloon)
  {
    //  get the object data
    var field = document.getElementById(fieldId);
    var obj = this;
    
    //  function to show the balloon
    function __ShowBalloon()
    {
      //  setup the balloon
      obj.errorBalloon.content = message;
      obj.errorBalloon.AutoCreate();
      
      //  create a new fader object if there in none, yet
      if (!obj.errorBalloonEffects)
        obj.errorBalloonEffects = new WATDivEffects(obj.name + '.errorBalloonEffects', obj.errorBalloon.divId);
        
      //  show the balloon
      obj.errorBalloonEffects.FadeIn(100, WATBrowserInfo.IsIE7 ? 1 : 350);
    }
    
    //  function to hide the balloon
    function __HideBalloon()
    {
      //  hide the balloon
      obj.errorBalloonEffects.FadeOut(0, WATBrowserInfo.IsIE7 ? 1 : 350);
    }
    
    //  create the events if the field has been found
    if (field)
    {    
      //  create the event handlers
      if (WATBrowserInfo.IsIE)
      {
        //  ... for Internet Explorer
        field.attachEvent('onclick', __ShowBalloon);
        field.attachEvent('onblur', __HideBalloon);
      }
      else
      {
        //  ... for other browsers
        field.addEventListener('click', __ShowBalloon, true);
        field.addEventListener('blur', __HideBalloon, true);
      }
    }
  }
}


//=====================================================================================================================
//  lightbox manager
//=====================================================================================================================

/**
 *  function to add a new lightbox to the desktop
 *
 *  @param string name  name of the lightbox
 *
 *  @return object  the function returns the created lightbox
 */
WATDesktop.prototype.CreateLightbox = function(name)
{
  //  create a new lightbox
  var lightbox = new WATDesktopLightbox(this.name, name);
  //  register the new lightbox
  this.lightboxes[name] = lightbox;
  //  return the created lightbox
  return lightbox;
}

/**
 *  function to get the lighbox with the passed name
 *
 *  @param string name  name of the requested lightbox
 *
 *  @return object  the function returns the requested lightbox of NULL if the lightbox with
 *                  the passed name does not exist
 */
WATDesktop.prototype.GetLightbox = function(name)
{
  //  search the lightbox
  for (var i in this.lightboxes)
    if (this.lightboxes[i].name == name) return this.lightboxes[i];

  //  the lightbox was not found
  return null;
}


//=====================================================================================================================
//  gadget control
//=====================================================================================================================

/**
 *  @param string key        key of the gadget
 *  @param object sheet      sheet in which the div object should be shown
 *  @param string className  css class name to be assigned to the div or null if no class name should be assigned
 *  @param string content    initial content of the div or null if no content should be set
 *  @param int    top        initial top position in pixels or -1 if no top position should be set
 *  @param int    left       initial left position in pixels or -1 if no left position should be set
 *  @param int    width      initial width of the div in pixels or -1 if no width should be assigned
 *  @param int    heigth     initial height of the div in pixels or -1 if no height should be assigned
 *
 *  @return object  the function returns the created gadget
 */
WATDesktop.prototype.CreateGadget = function(key, sheet, className, content, top, left, width, height)
{
  //  create a new gadget
  var gadget = new WATDesktopGadget(this.name, sheet, key, className, content, top, left, width, height);
  gadget.gadgetControlAjaxHandler = this.gadgetControlAjaxHandler;
  gadget.gadgetControlSessionParam = this.gadgetControlSessionParam;
  //  register the new gadget
  this.gadgets[key] = gadget;
  //  return the created gadget
  return gadget;
}

/**
 *  function to get the gadget with the passed key
 *
 *  @param string key  key of the required gadget
 *
 *  @return object  the function returns the gadget with the passed key or null if the gadget was not found
 */
WATDesktop.prototype.GetGadget = function(key)
{
  //  search the gadget
  for (var i in this.gadgets)
    if (i == key && this.gadgets[i]) return this.gadgets[i];

  //  the gadget was not found
  return null;
}

/**
 *  function to remove the gadget with the passed key
 *
 *  @param string key  key of the gadget to remove
 */
WATDesktop.prototype.RemoveGadget = function(key)
{
  for (var i in this.gadgets)
    if ((i == key || key == null) && this.gadgets[i])
    {
      //  remove all gadgets at the same time without fading if no key has been passed
      if (key)
      {
        //  fade the gadget out
        this.gadgets[i].divEffects.FadeOut(150);
        setTimeout(this.name + '.gadgets["' + i + '"].Remove(); ' + this.name + '.gadgets["' + i + '"] = null;', 500);
      }
      else
      {
        //  remove the gadget
        this.gadgets[i].Remove();
        this.gadgets[i] = null;
      }
    }
}

WATDesktop.prototype.ResizeGadgets = function(sheet)
{
  if (sheet.grid && sheet.grid.width != null)
  {
    for (var i in this.gadgets)
      if (this.gadgets[i] && this.gadgets[i].sheet == sheet)
      {
        var gadget = this.gadgets[i];
        
        var newLeft = gadget.divEffects.GetLeft(false);
        var newWidth = gadget.divEffects.GetWidth();
        var newHeight = gadget.divEffects.GetHeight();
        var newTop = gadget.divEffects.GetTop(false);
  
        var dist = newLeft % sheet.grid.colWidth;
  
        if (dist < (sheet.grid.colWidth / 2)) newLeft -= dist;
        else newLeft += (sheet.grid.colWidth - dist);
        
        var dist = newWidth % sheet.grid.colWidth;
        if (dist < (sheet.grid.colWidth / 2)) newWidth -= dist;
        else newWidth += (sheet.grid.colWidth - dist);
        
        var column = newLeft / sheet.grid.colWidth;
        
        gadget.column = column;
        gadget.colSpan = newWidth / sheet.grid.colWidth;
        
        if ((column+1) < sheet.grid.colCount) newWidth -= Math.floor((sheet.grid.verticalSpace / 2));
        if (column > 0) newLeft += Math.ceil((sheet.grid.verticalSpace / 2));
        
        
        var dist = newTop % sheet.grid.rowHeight;
        if (dist < (sheet.grid.rowHeight / 2)) newTop -= dist;
        else newTop += (sheet.grid.rowHeight - dist);
        
        
        var dist = newHeight % sheet.grid.rowHeight;
        if (dist < (sheet.grid.rowHeight / 2)) newHeight -= dist;
        else newHeight += (sheet.grid.rowHeight - dist);
        
        
        //newLeft += sheet.grid.paddingLeft;
        //newWidth -= (sheet.grid.paddingLeft + sheet.grid.paddingRight);
        
        newHeight -= (sheet.grid.paddingTop + sheet.grid.paddingBottom);
        newTop += sheet.grid.paddingTop;
        
        gadget.SetSize(sheet.grid.marginLeft + newLeft, newTop, newWidth, newHeight);
      }
  }
}
