/* 
  Algo: a dekstop environment look-a-like in your web browser
  Copyright (C) 2009  Niels Serup
  
	This file is part of Algo.

	Algo is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	Algo is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with Algo.  If not, see <http://www.gnu.org/licenses/>.
*/

/*
  The screen class creates the screen on which all the windows appear.
  As a matter of fact, the screen class simply serves as a layer for adding
  windows. That's all. */
function screen() {
  this.elem = document.createElement('div')
  this.elem.className = 'area'
  this.elem.style.width = '100%' // Height determined by JavaScript later on
  wrapper.appendChild(this.elem)
  
  /* len and olen dynamically increases as new windows are opened. But while
     len is decreased when windows are closed, olen is never decreases. This
     proves helpful when the windows in objects/iframes must be able to access
     their own windows. */
  this.len = 0
  this.olen = 0
  /* wndpos holds information about the windows on the screen. Each wndpos
     entry is a link to a scr_window class. wndpos keeps the links in their
     index order. */
  this.wndpos = new Array()
  
  /* It is neccessary to create an overlay, as the window objects/iframes will
     catch focus if the mouse is moved over them. The overlay is on whenever a
     window is being moved or adjusted */
  this.overlay = document.createElement('div')
  this.overlay.className = 'overlay'
  this.elem.appendChild(this.overlay)
}

screen.prototype.rethink = function() {
  // rethink() reorganises the screen top and height based on the navbars.
  var navil = navi.length
  var mh, th, borders, bl, border
  mh = 0
  th = 0
  /* The following loop uses the height and the border height of the navbars
     to compute the space on which the screen should be positioned. */
  for (var i = 0; i < navil; i++) {
    border = 0
    borders = navi[i].border
    bl = borders.length
    for (var ii = 0; ii < bl; ii += 2) {
      border += borders[ii]
    }
    mh += navi[i].height
    if (navi[i].pos[0] != -1)
      th += navi[i].height + border
    if (navi[i].pos[0] != -1 || navi[i].pos[2] != -1)
      mh += border
  }
  // bi = the heights of the navbars plus the border heights of the navbars
  this.bi = mh
  this.elem.style.top = th + 'px'
}

screen.prototype.update = function() {
  // Updates width and height and adjusts the height
  this.wh()
  this.elem.style.height = sh + 'px'
}

screen.prototype.wh = function() {
  // Get screen width and height
  if (self.innerHeight) {
    h = self.innerHeight
    w = self.innerWidth
  }
  else if (document.documentElement && document.documentElement.clientHeight) {
    h = document.documentElement.clientHeight
    w = document.documentElement.clientWidth
  }
  else if (document.body) {
    h = document.body.clientHeight
    w = document.body.clientWidth
  }
  
  // sh = screen height - navbars heights. The height of the screen area is sh
  sh = h - this.bi
}

screen.prototype.change_focus = function(num, det) {
  /* This function changes focus to the window specified in "num". "det" is a
     special identifier that tells this function what to do. Or whatever. */
  if (det == undefined) var det = 0
  
  var num = num * 1
  for (var i = 0; i < this.len; i++) {
    // Delete link from the wndpos list
    if (this.wndpos[i] == num) this.wndpos.splice(i, 1)
  }
  /*
    if det == 0: add window to front
    if det == 1: add window to back
    if det == 2: remove and close window
  */
  if (det == 0)
    this.wndpos.splice(0, 0, num)
  else if (det == 1)
    this.wndpos.splice(this.len, this.len, num)
  else if (det == 2) {
    this.len--
    this.elem.removeChild(wnds[num].elem)
    navi[posis['appboxes']].appboxes.removeChild(wnds[num].appbox)
    
    for (i = 0; i < this.len; i++) {
      if (this.wndpos[i] > num) {
        wnds[this.wndpos[i]].renum(-1) // Readjust windows with a higher index
        this.wndpos[i]--
      }
    }
    
    // Different actions based on different variables
    if (moving_window > num) moving_window--
    else if (moving_window == num) this.move_end()
    
    if (adjusting_window > num) adjusting_window--
    else if (adjusting_window == num) this.adjust_end()
    
    delete wnds[num]
    wnds.splice(num, 1)
    
  }
  // This function has no done anything visually. setindex takes care of that.
  this.setindex()
}

screen.prototype.setindex = function() {
  /* This function writes any changes made in the classes in the wndpos to the
     screen. If focus has changed from one window to another, setindex makes
     the user see that. */
  for (var i = 1; i < this.len; i++) {
    wnds[this.wndpos[i]].elem.style.zIndex = this.len - i + 1
    wnds[this.wndpos[i]].elem.id = ''
    wnds[this.wndpos[i]].appbox.className = ''
  }
  if (this.len > 0) {
    // The first window in the hierarchy gets the focus
    wnds[this.wndpos[0]].elem.style.zIndex = this.len + 2
    wnds[this.wndpos[0]].elem.id = 'active'
    wnds[this.wndpos[0]].appbox.className = ''
    this.overlay.style.zIndex = this.len + 1
  }
  
  // vis will turn true if any window is visible
  var vis = false
  for (i = 0; i < this.len; i++) {
    if (wnds[i].visible) vis = true
  }
  // Only make the current window current if at least one window is visible
  if (vis) wnds[this.wndpos[0]].appbox.className = 'current'
  
  // Check if there's enough space for the appboxes
  navi[posis['appboxes']].check_abs_height(true)
}

screen.prototype.set_overlay = function() {
  this.overlay.style.display = 'block'
}

screen.prototype.del_overlay = function() {
  this.overlay.style.display = 'none'
}

screen.prototype.move_start = function(what) {
  /* "move_start" sets the global value "moving_window" to the active window
     and thereby makes it recognisable by the set_coor function. */
  moving_window = what * 1
  
  /* The overlays are needed to keep the objects/iframes from getting the
     mouse focus. In theory this should not happen, but as the mouse is often
     moved faster than the window, this happens.
     There are two overlays: one that covers the window and on that covers the
     other windows. */
  wnds[moving_window].cn('data_overlay').style.display = 'block'
  this.set_overlay()
  
  // These are needed later on to determine the position of the window.
  diff_x = x - wnds[moving_window].elem.offsetLeft
  diff_y = y - wnds[moving_window].elem.offsetTop
}

screen.prototype.move_end = function() {
  if (moving_window > -1)
    wnds[moving_window].cn('data_overlay').style.display = 'none'
  moving_window = -1
  this.blurfocus()
}

screen.prototype.adjust_start = function(what, dir) {
  /* This is the same as "move_start" except that this does not start moving
     the window, but instead it starts adjusting (resizing) it. */
  adjusting_window = what * 1
  adjusting_dir = dir * 1
  wnds[adjusting_window].cn('data_overlay').style.display = 'block'
  this.set_overlay()
  
  // Different variables are set depending on the direction of the adjusting.
  /*
    The directions are:
    0: top-left
    1: top
    2: top-right
    3: right
    4: bottom-right
    5: bottom
    6: bottom-left
    7: left
    
    If the resize direction is diagonal, both of the below options are true.
  */
  if (adjusting_dir != 1 && adjusting_dir != 5) {
    // If vertical
    start_x = x
    start_w = wnds[adjusting_window].width
    diff_x = start_x - wnds[adjusting_window].elem.offsetLeft
  }
  if (adjusting_dir != 3 && adjusting_dir != 7) {
    // If horizontal
    start_y = y
    start_h = wnds[adjusting_window].height
    diff_y = start_y - wnds[adjusting_window].elem.offsetTop
  }
}

screen.prototype.adjust_end = function() {
  if (adjusting_window > -1)
    wnds[adjusting_window].cn('data_overlay').style.display = 'none'
  adjusting_window = -1
  adjusting_dir = -1
  this.blurfocus()
}

screen.prototype.blurfocus = function() {
  // Hides the overlay and applies the fix
  this.del_overlay()
  highlightfix.focus()
  highlightfix.select()
}

screen.prototype.setwindow = function(a, b, c, d, e, f, g, h, i, j, k, l, m, n) {
  // This function is the one that must be called when creating a new window.
  wnds[wnds.length] = new scr_window(a, b, c, d, e, f, g, h, i, j, k, l, m, n)
  
  // Positions itself at the front
  this.wndpos.splice(0, 0, this.len)
  this.len++
  this.olen++
  this.setindex()
}

screen.prototype.move_window = function() {
  // Moves the window based on current and earlier set variables
  var cx = x - diff_x
  if (cx < -diff_x) cx = -diff_x
  else if (cx > w - diff_x) cx = w - diff_x
  var cy = y - diff_y
  if (cy < 0) cy = 0
  else if (cy > sh - scr.hheight) cy = sh - scr.hheight
  if (scr.len > moving_window) {
    wnds[moving_window].elem.style.left = cx + 'px'
    wnds[moving_window].elem.style.top = cy + 'px'
  }
}

screen.prototype.adjust_window = function() {
  // Adjusts the window based on current and earlier set variables
  
  // This function uses the same direction principle as "adjust_start".
  if (adjusting_dir != 1 && adjusting_dir != 5) {
    var cx, cw, cxs
    cxs = false
    if (adjusting_dir == 0 || adjusting_dir == 6 || adjusting_dir == 7) {
      // If to the left
      cx = x - diff_x
      cw = start_w + start_x - x
      if (x - diff_x < 0) {
        cx = 0
        cxs = true
      }
    }
    else {
      // If to the right
      cx = start_x - start_w + start_w - diff_x
      cw = start_w + x - start_x
      if (x + start_w - diff_x > w) cxs = true
    }
    
    if (cw < width_min) cxs = true
    
    if (!cxs && scr.len > adjusting_window) {
      wnds[adjusting_window].elem.style.left = cx + 'px'
      wnds[adjusting_window].width = cw
    }
  }
  
  if (adjusting_dir != 3 && adjusting_dir != 7) {
    var cy, ch, cys
    cys = false
    if (adjusting_dir == 0 || adjusting_dir == 1 || adjusting_dir == 2) {
      // If upwards
      cy = y - diff_y
      ch = start_h + start_y - y
      if (y - diff_y < 0) {
        cy = 0
        cys = true
      }
    }
    else {
      // If downwards
      cy = start_y - start_y + start_y - diff_y
      ch = start_h + y - start_y
      if (y + start_h - diff_y > sh) cys = true
    }
    
    if (ch < height_min) cys = true
    
    if (!cys && scr.len > adjusting_window) {
      wnds[adjusting_window].elem.style.top = cy + 'px'
      wnds[adjusting_window].height = ch
    }
  }
  
  // Update the window position
  wnds[adjusting_window].update()
}

screen.prototype.set_coor = function(e) {
  /* This function sets the global coordinates of the screen. If a window
     is eiher being moved or adjusted, this function calls the "move_window"
     or "adjust_window" functions */
  if (!e) var e = window.event
  if (e.pageX || e.pageY) {
    x = e.pageX
    y = e.pageY
  }
  else if (e.clientX || e.clientY) {
    x = e.clientX + document.body.scrollLeft
    y = e.clientY + document.body.scrollTop
  }
  
  if (moving_window != -1)
    scr.move_window()
  else if (adjusting_window != -1)
    scr.adjust_window()
}