/*
 * Dynamically detects , re-sizes , and re-positions 'absolute positioned CSSP widgets' using a 
 * simple layout constraint and resource sharing algorithm.
 */

// Class used to define a layout constraint
function LayoutConstraint () {
  var mySelf = this

  mySelf.obj = null 
  mySelf.objdoc = null
  mySelf.depth = 0
  mySelf.resized = false
  mySelf.x = 0
  mySelf.y = 0
  mySelf.w_group = ''
  mySelf.h_group = ''
  mySelf.w_weight = 0
  mySelf.h_weight = 0
  mySelf.w_by_proxy = false
  mySelf.h_by_proxy = false
  mySelf.parent = null
  mySelf.t_is_constrained = false
  mySelf.b_is_constrained = false
  mySelf.l_is_constrained = false
  mySelf.r_is_constrained = false
  mySelf.h_is_constrained = false
  mySelf.w_is_constrained = false
  mySelf.temp_visible = false
  mySelf.t_constraint = 0
  mySelf.b_constraint = 0
  mySelf.l_constraint = 0
  mySelf.r_constraint = 0
  mySelf.h_constraint = 0
  mySelf.w_constraint = 0

  return mySelf
}

// Class used to define a layout group
function LayoutGroup () {
  mySelf = this

  mySelf.group_name = ''
  mySelf.group_plane = ''
  mySelf.group_weight = 0
  mySelf.group_delta = 0

  return mySelf
}

// Class used to resize a document
function LayoutSizer() {

  var mySelf = this

  // Minimum window size X & Y (pixels)
  mySelf.min_window_size = new Array(2)

  // "Table" of layout constraint objects initialized by parsing the 
  // 'widget' hierarchy of the document
  mySelf.layout_constraints = new Array()

  // "Table" of layout group objects initialized by parsing the
  // 'widget' hierarchy of the document
  mySelf.layout_groups = new Array()

  function findLayoutGroup(group_name,xOrY) {
    for (i = 0; i < mySelf.layout_groups.length; i ++ ) {
      var lgtmp = mySelf.layout_groups[i]
      if ( lgtmp.group_name == group_name && lgtmp.group_plane == xOrY) {
         return lgtmp
      }
    }
    return null
  }
  mySelf.findLayoutGroup = findLayoutGroup

  function make_constraint(hdlParent,hdlChild,depth) {
    var i = 0
    var lce = ''
    var wgt = 0

    var layout_group = null

    var layout_constraint = new LayoutConstraint()
    layout_constraint.obj = hdlChild
    layout_constraint.objdoc = hdlChild.ownerDocument
    layout_constraint.parent = hdlParent
    layout_constraint.x = getX(hdlChild)
    layout_constraint.y = getY(hdlChild)
    layout_constraint.depth = depth

    /* Progress dynresize contains code here to reset the
     * 'hdlParent' variable to the nearest 'ancestor' in the
     * tree that is not a field group widget (which we don't
     * want to resize in the progress widget model).  We
     * are skipping this code, but it might be needed later
     * if there are intermediate containers we want to skip
     */

    // Mozilla compatibility block
    if ( (! hdlChild.constraints) && hdlChild.getAttribute('constraints') ) {
      hdlChild.constraints = hdlChild.getAttribute('constraints')
      hdlChild.ygroup = hdlChild.getAttribute('ygroup')
      hdlChild.xgroup = hdlChild.getAttribute('xgroup')
    }
    // End MCB

    if ( (! hdlChild.constraints ) ) { return }

    for ( i = 0; i < hdlChild.constraints.split(',').length; i++ ) {
      lce = hdlChild.constraints.split(',')[i]

      switch(lce) {
        case 'T':
          layout_constraint.t_is_constrained = true
          layout_constraint.t_constraint = getY(hdlChild)
          break
        case 'B':
          layout_constraint.b_is_constrained = true
          layout_constraint.b_constraint = getHeight(hdlParent) - ( getY(hdlChild) + getHeight(hdlChild) )
          break
        case 'L':
          layout_constraint.l_is_constrained = true
          layout_constraint.l_constraint = getX(hdlChild)
          break
        case 'R':
          layout_constraint.r_is_constrained = true
          layout_constraint.r_constraint = getWidth(hdlParent) - ( getX(hdlChild) + getWidth(hdlChild) )
          break
      }
    }

    if ( hdlChild.ygroup ) {
      /* Set the group */
      layout_constraint.h_group = hdlChild.ygroup.split('/')[0]

      /* Set the weight */
      if ( hdlChild.ygroup.split('/').length > 1 ) {
        wgt = parseInt(hdlChild.ygroup.split('/')[1])
      }
      /* If widget is not growable, assign no weight */
      else if (! (layout_constraint.b_is_constrained && layout_constraint.t_is_constrained) ) { wgt = 0 }
      /* Default weight */
      else wgt = 1

      layout_constraint.h_weight = wgt

      /* TODO:  Change following iteration to use a dictionary lookup instead */
      layout_group = findLayoutGroup(layout_constraint.h_group,'Y')
      if (! layout_group) {
        layout_group = new LayoutGroup()
        layout_group.group_name = layout_constraint.h_group
        layout_group.group_plane = 'Y'
        // Add the new layout group to the array of layout groups
        mySelf.layout_groups[mySelf.layout_groups.length] = layout_group
      }

      /* Mark if this widget is a proxy in the group ( it grows , but does not contribute to overall growth
       * -- imagine a widget in a vertical group next to another in the same group.  One of them doesn't need
       * -- to add to the total growth, because the other one has already accounted for it by proxy
       */
      if ( hdlChild.ygroup.split('/').length > 2) {
        layout_constraint.h_by_proxy = true
      }
      else {
        layout_constraint.h_by_proxy = false
        /* Add this weight to the total weight specified for the group in this plane */
        layout_group.group_weight += wgt
      }

    } /* ygroup processing block */

    if ( hdlChild.xgroup ) {
      /* Set the group */
      layout_constraint.w_group = hdlChild.xgroup.split('/')[0]

      /* Set the weight */
      if ( hdlChild.xgroup.split('/').length > 1 ) {
        wgt = parseInt(hdlChild.xgroup.split('/')[1])
      }
      /* If widget is not growable, assign no weight */
      else if (! (layout_constraint.l_is_constrained && layout_constraint.r_is_constrained) ) { wgt = 0 }
      /* Default weight */
      else wgt = 1

      layout_constraint.w_weight = wgt

      /* TODO:  Change following iteration to use a dictionary lookup instead */
      layout_group = findLayoutGroup(layout_constraint.w_group,'X')
      if (! layout_group) {
        layout_group = new LayoutGroup()
        layout_group.group_name = layout_constraint.w_group
        layout_group.group_plane = 'X'
        // Add the new layout group to the array of layout groups
        mySelf.layout_groups[mySelf.layout_groups.length] = layout_group
      }

      /* Mark if this widget is a proxy in the group ( it grows , but does not contribute to overall growth
       * -- imagine a widget in a vertical group next to another in the same group.  One of them doesn't need
       * -- to add to the total growth, because the other one has already accounted for it by proxy
       */
      if ( hdlChild.xgroup.split('/').length > 2) {
        layout_constraint.w_by_proxy = true
      }
      else {
        layout_constraint.w_by_proxy = false
        /* Add this weight to the total weight specified for the group in this plane */
        layout_group.group_weight += wgt
      }
    } /* xgroup processing block */

    if (layout_constraint.r_is_constrained && layout_constraint.l_is_constrained) {
      layout_constraint.w_is_constrained = true
    }
    if (layout_constraint.t_is_constrained && layout_constraint.b_is_constrained) {
      layout_constraint.h_is_constrained = true
    }

    mySelf.layout_constraints[mySelf.layout_constraints.length] = layout_constraint

  } // make_constraint
  mySelf.make_constraint = make_constraint

  function apply_resize(top_container) {
    var lc = null // alternate reference for layout_constraint
    var layout_group
    var x = 0
    var delta = 0
    var c = 0

    /* TODO: Put code to enforce minimum window size here */
    if (top_container.layout_size_x < mySelf.min_window_size[0]) {
      return
    }
    if (top_container.layout_size_y < mySelf.min_window_size[1]) {
      return
    }

    /* Progress code has section here to avoid dynamic fit errors, which
     * should be 'unique' to the progress environment (because they're 
     * silly).  Omitted in JS version
     */

    /* * * Adjust Horizontal position and size * * */

    // Iterate over all constraints and get rid of any that are for documents that have been
    // unloaded already
    /*
    var new_constraints = []
    for( c = 0; c < mySelf.layout_constraints.length; c++) {
      lc = mySelf.layout_constraints[c]
      var doc = lc.obj
    */

    // Need to access layout constraints sorted 1st by X position (left to right),
    // then by Y position desc (bottom to top)
    // Following routine sorts the layout_constraint array accordingly
    function sortLCByXascYdesc(lc1,lc2) {
      if (lc1.x > lc2.x) return 1
      if (lc1.x < lc2.x) return -1
      if (lc1.x == lc2.x) {
        if (lc1.y < lc2.y) return 1
        if (lc1.y > lc2.y) return - 1
      }
      return 0
    }
    mySelf.layout_constraints.sort(sortLCByXascYdesc)

    for( c = 0; c < mySelf.layout_constraints.length; c++) {
      lc = mySelf.layout_constraints[c]

      if (lc.w_is_constrained) {
        var oldwidth = 0
        var newwidth = 0

        oldWidth = getWidth(lc.obj)
        newWidth = getWidth(lc.parent) - ( getX(lc.obj) + lc.r_constraint )

        /* Get the delta -- this is the TOTAL amount of growth (or shrinkage) available to the object */
        delta = newWidth - oldWidth

        if (lc.w_group != "") {
          layout_group = findLayoutGroup(lc.w_group,'X')
          delta = (delta * ( lc.w_weight / layout_group.group_weight ) )
        }

        /* Assign the new width based upon calculated delta */
        setWidth(lc.obj, getWidth(lc.obj) + delta )

        if (lc.w_group != "") {
          /* Assign the new X position based upon the total growth distributed so far */
          setX(lc.obj, getX(lc.obj) + layout_group.group_delta)
          /* DON'T FORGET THIS.  Recalculate the right constraint (it's changed now ) */
          lc.r_constraint = getWidth(lc.parent) - ( getX(lc.obj) + getWidth(lc.obj) )

          /* Add this delta to the total */
          if (! lc.w_by_proxy) {
            layout_group.group_delta += delta
          }
        } /* ! lc.w_by_proxy */
      } /* lc.w_is_constrained */
      else if (lc.r_is_constrained) {
        if (lc.w_group == '') { 
          setX(lc.obj, getWidth(lc.parent) - ( lc.r_constraint + getWidth(lc.obj)  ) )
        }
        /* Get the total weight of the group this object is in */
        layout_group = findLayoutGroup(lc.w_group,'X')
        if (layout_group) {
          setX(lc.obj, getX(lc.obj) + layout_group.group_delta)
          lc.r_constraint = getWidth(lc.parent) - ( getX(lc.obj) + getWidth(lc.obj) )
        }

      }

      // Keep track of the fact the object was resized
      lc.resized = true

    } /* For each layout_constraint sorted by X , Y desc */

    /* * * Adjust Vertical position and size * * */

    // Need to access layout constraints sorted 1st by Y position (top to bottom),
    // then by X position desc (right to left)
    // Following routine sorts the layout_constraint array accordingly
    function sortLCByYascXdesc(lc1,lc2) {
      if (lc1.y > lc2.y) return 1
      if (lc1.y < lc2.y) return -1
      if (lc1.y == lc2.y) {
        if (lc1.x < lc2.x) return 1
        if (lc1.x > lc2.x) return - 1
      }
      return 0
    }
    mySelf.layout_constraints.sort(sortLCByYascXdesc)

    for( c = 0; c < mySelf.layout_constraints.length; c++) {
      lc = mySelf.layout_constraints[c]

      /* If height is Constrained , adjust position and/or size as necessary */
      if (lc.h_is_constrained) {
        var oldheight = 0
        var newheight = 0

        /* Get old height , and new height */
        oldheight = getHeight(lc.obj)
        newheight = getHeight(lc.parent) - ( getY(lc.obj) + lc.b_constraint )

        /* Get the delta -- this is the TOTAL amount of growth (or shrinkage) available to the object */
        delta = newheight - oldheight

        if (lc.h_group != '') {
          /* Get the total weight of the group this object is in */
          layout_group = findLayoutGroup(lc.h_group,'Y')

          /* Distribute the delta by the weight of this object in proportion to total weight
           * of the group
           */
          delta = (delta * ( lc.h_weight / layout_group.group_weight ) ) 
        }

        /* Assign the new height based upon calculated delta */
        setHeight(lc.obj, getHeight(lc.obj) + delta  )

        if (lc.h_group != '') { 
          /* Assign the new y position based upon the total growth distributed so far */
          setY(lc.obj, getY(lc.obj) + layout_group.group_delta )

          /* DON'T FORGET THIS.  Recalculate the bottom constraint (it's changed now ) */
          lc.b_constraint = getHeight(lc.parent) -  ( getY(lc.obj) + getHeight(lc.obj) )

          /* Add this delta to the total */
          if (! lc.h_by_proxy) { 
            layout_group.group_delta += delta 
          }
        } /* lc.h_group != '' */

      } /* lc.h_is_constrained */
      else if (lc.b_is_constrained) {

        if (lc.h_group == '') {
          setY(lc.obj, getHeight(lc.parent) - ( lc.b_constraint + getHeight(lc.obj) ) )
        }

        layout_group = findLayoutGroup(lc.h_group,'Y')
        if (layout_group) {
          /* Assign the new y position based upon the total growth distributed so far */
          setY(lc.obj, getY(lc.obj) + layout_group.group_delta )
          /* DON'T FORGET THIS.  Recalculate the right constraint (it's changed now ) */
          lc.b_constraint = getHeight(lc.parent) - ( getY(lc.obj) + getHeight(lc.obj) )
        }
      } /* lc.b_is_constrained */

      // Keep track of the fact the object was resized
      lc.resized = true
    } /* for each layout constraint sorted by Y , X desc */

    /* Progress version of dynresize.i has a code block here meant to restore the 
     * virtual height & width of all frame widgets in progress.  Our version 
     * never screwed those values up in the first place so ignoring....
     */

    /* Reset our group_delta's for next time */
    layout_group = null
    for (var c = 0; c < mySelf.layout_groups.length; c++) {
      layout_group = mySelf.layout_groups[c]
      layout_group.group_delta = 0
    }


    // Iterate once more through all layout constraints that were resized, and notify the widgets
    // in case they need to do any internal housekeeping.
    for (var c = 0; c < mySelf.layout_constraints.length; c ++) {
      var lc = mySelf.layout_constraints[c]
      if (lc.resized == true) {
        lc.resized == false
        top.glbDict.getMyInst(lc.obj).baseApplyResize()
      }
    }
  } // apply_resize
  mySelf.apply_resize = apply_resize

  return mySelf
} // Class LayoutSizer

// All of the objects that we're dealing with will need convenience methods
// for setting & getting X , Y , width, and height in a normalized way.  Definitions
// for these follow.
function getX(obj) {
  if (obj.tagName == 'SPAN') {
    return parseInt(obj.style.left)
  }
  if (obj.tagName == 'BODY') {
    return 0
  }
  alert('getX(?)')
}

function setX(obj,val) {
  if (obj.tagName == 'SPAN') {
    obj.style.left = val + 'px'
    return
  }
  alert('setX:' + obj.tagName)
}

function getY(obj) {
  if (obj.tagName == 'SPAN') {
    return parseInt(obj.style.top)
  }
  if (obj.tagName == 'BODY') {
    return 0
  }
  alert('getY(?)')
}

function setY(obj,val) {
  if (obj.tagName == 'SPAN') {
    obj.style.top = val + 'px'
    return
  }
  alert('setY(?)')
}

function getWidth(obj) {
  if (obj.tagName == 'SPAN') {
    var fc = obj.firstChild
    while (fc && fc.nodeType == 3) {  // ignore text nodes when finding the first child
      fc = fc.nextSibling
    }
    return parseInt(fc.style.width)
  }
  if (obj.tagName == 'BODY') {
    return parseInt(obj.getAttribute('layout_size_x'))
  }
  alert('getWidth(?)')
}

function setWidth(obj,val) {
  if (obj.tagName == 'SPAN') {
    var fc = obj.firstChild
    while (fc && fc.nodeType == 3) {  // ignore text nodes when finding the first child
      fc = fc.nextSibling
    }
    if (val < 0 ) {
    }
    else {
      fc.style.width = val + 'px'
    }
    return
  }
  alert('setWidth:' + obj.tagName)
}

function getHeight(obj) {
  if (obj.tagName == 'SPAN') {
    var fc = obj.firstChild
    while (fc && fc.nodeType == 3) {  // ignore text nodes when finding the first child
      fc = fc.nextSibling
    }
    return parseInt(fc.style.height)
  }
  if (obj.tagName == 'BODY') {
    var x = parseInt(obj.getAttribute('layout_size_y'))
    return x
  }
  alert('getHeight(?)')
}

function setHeight(obj,val) {
  if (obj.tagName == 'SPAN') {
    var fc = obj.firstChild
    while (fc && fc.nodeType == 3) {  // ignore text nodes when finding the first child
      fc = fc.nextSibling
    }
    if (val < 0 ) {
    }
    else {
      fc.style.height = val + 'px'
    }
    return
  }
  alert('setHeight:' + obj.tagName)
}

function dynresize_init() {
  /* The HTML body node is our 'top_parent'.  Get it, and
   * assign necessary helper functions
   */
  var top_parent = arguments[0][1].body

  var ls = new LayoutSizer()

  var spans = top_parent.getElementsByTagName('span')

  function set_constraints() {
    /* Get a list of all of the SPAN elements in the HTML body that have
     * an attribute of 'onserver' set to 'true'
     * These are all of the items that need to be constrained.
     */
    for (var s = 0 ; s < spans.length ; s++ ) {
      var child = spans[s]
      if (child.getAttribute('onserver')) {
        // Call make_constraint on the object
        ls.make_constraint(top_parent,child,1)
      }
    }
  }
  set_constraints()
  this.set_constraints = set_constraints


  function dosize () {
    var pWidth = top_parent.clientWidth
    var pHeight = top_parent.clientHeight

    if ( document.all && (!window.opera) ) {
      var bw = top_parent.ownerDocument.getElementById('bodywrap')
      bw.style.height = pHeight + 'px'
      bw.style.width = pWidth + 'px'
    }

    // Corrects really wierd Mozilla bug in child windows
    if ( (!document.all) && window.opener) {
      pHeight = top_parent.ownerDocument.defaultView.innerHeight
      pWidth = top_parent.ownerDocument.defaultView.innerWidth
    }
    //alert('inside dosize for doc ' + top_parent.ownerDocument.location)
    top_parent.setAttribute('layout_size_x', parseInt(pWidth))
    top_parent.setAttribute('layout_size_y', parseInt(pHeight))
    ls.apply_resize(top_parent)
    top.glbDict.uwEventController.postEvent('resize',top_parent.ownerDocument)
  }
  this.dosize = dosize
  if (top_parent.ownerDocument.defaultView) {
    // Mozilla
    top_parent.ownerDocument.defaultView.onresize = dosize
  }
  else {
    // IE
    top_parent.onresize = dosize
  }

  top_parent.sizer = this

  top.glbDict.forceResize = dosize

  // Set minimum window size
  if (top_parent.min_size_x) {
    ls.min_window_size[0] = Math.min(parseInt(top_parent.getAttribute('min_size_x')),parseInt(top_parent.getAttribute('layout_size_x')))
  }
  if (top_parent.min_size_y) {
    ls.min_window_size[1] = Math.min(parseInt(top_parent.getAttribute('min_size_y')),parseInt(top_parent.getAttribute('layout_size_y'))) 
  }

  // Initialize the screen with the initial size of 
  // the body
  dosize()


  // Post a global event to let the rest of the framework know dynresize has finished
  // initializing a document, in case anything is waiting...
  top.glbDict.postUWEvent('dynresize_initialized' , arguments[0][1] , spans )

}

// Make dynresize_init listen for doc_init events
//top.glbDict.uwEventController.addListener('doc_init' , dynresize_init )

if (! top.glbDict.dynResizeInstalled) {
  // Make dynresize_init listen for doc_init events
  top.glbDict.uwEventController.addListener('doc_init' , dynresize_init )
  top.glbDict.dynResizeInstalled = true
}

