/* 
 * Gaia Ajax Widgets, an Ajax Widget Library for ASP.NET 2.0
 * Copyright (C) 2007  Frost Innovation AS
 * All rights reserved.
 * 
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as 
 * published by the Free Software Foundation.
 * 
 * Or if you have purchased the "Professional Edition" from Frost Innovation
 * it is distributed to you in person under the Gaia Commercial License
 * which makes it possible for you to create closed source applications
 * and still be able to distribute those applications without creating 
 * restrictions for your source code.
 * 
 * Unless you're developing GPL software you should and probably legally
 * have to purchase a license of the Gaia Commercial License since otherwise
 * you might be forced to GPL license your derived works.
 * 
 * This program 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 find a copy of both the GPL version 2 and the 
 * Gaia Commercial License on disc where you have extracted these files.
 * If not visit http://www.gnu.org for the GPL version or 
 * http://ajaxwidgets.com for the Gaia Commercial License.
 * 
 * Breaking the terms of whatever license you're entitled to use will cause
 * prosecution by Frost Innovation AS. If possible we will demand to settle any 
 * law suits at a court in Norway.
 * 
 */




/* ---------------------------------------------------------------------------
   Class basically wrapping the Gaia Ajax WebWidgets Panel class.
   --------------------------------------------------------------------------- */
WebControl.Window = function(element, options){
  this.initialize(element, options);
}

WebControl.Window._visibleWindows = new Array();

WebControl.Window.prototype = Object.extend(new WebControl(),{

  // "Constructor"
  initialize: function(element, options){
    // Calling base class constructor
    this.baseInitializeWebControl(element, options);

    // Setting width and height, NOTE DO THIS FIRST to avoid flickering...
    this.options.width = this.options.width || 600;
    this.options.height = this.options.height || 400;

    // Setting initial width and height
    Position.absolutize(this.element);
    this.element.setStyle({
      width: (parseInt(this.options.width, 10) + this.options.widthOfBorders) + 'px', 
      height: parseInt(this.options.height, 10) + 'px'
    });

    // Checking to see if we're about to CENTER the form, do EARLY to avoid flickering...
    if( this.options.center == true )
      this.center();
    else {
      if( this.options.left || this.options.top ){
        this.options.left = (this.options.left || 0);
        this.options.top = (this.options.top || 0);
        this.setLocation(this.options.left, this.options.top);
      }
    }

    // Checking to see if window is initially visible
    this.setVisible(this.options.visible);

    // Making it movable
    if( this.options.draggable == true ){
      this.draggable = new Draggable(this.element, {
        handle:this.element.id+'_HANDLE', 
        starteffect:Prototype.emptyFunction, 
        endeffect:Prototype.emptyFunction
      });
    }

    // Setting the minimizable properties
    if( this.options.minimizable ){
      Element.observe($(this.element.id+'_MINIMIZER'), 'click', function(){
        var inner = $(this.element.id.substr(0,this.element.id.length-4)+'_CONTENT_TBL');
        Element.toggle(inner);
      }.bind(this));
    }

    // Setting the maximizable properties
    if( this.options.maximizable ){
      Element.observe($(this.element.id+'_MAXIMIZER'), 'click', function(){
        var inner = $(this.element.id.substr(0,this.element.id.length-4));

        if( this.isMaximized ){
          // Restoring
          inner.setStyle({
            width: this.isMaximized.innerWidth,
            height: this.isMaximized.innerHeight
          });
          this.element.setStyle({
            width: this.isMaximized.width, 
            height: this.isMaximized.height,
            top:this.isMaximized.top,
            left:this.isMaximized.left
          });
          delete this.isMaximized;
        } else {
          // Maximizing
          this.isMaximized = {
            width:this.element.style.width, 
            height:this.element.style.width, 
            innerWidth:inner.style.width, 
            innerHeight:inner.style.height,
            top: this.element.style.top,
            left: this.element.style.left};
          var pageSize = this.getPageSize();
          inner.setStyle({
            width: (pageSize.pageWidth - this.options.widthOfBorders) + 'px',
            height: (pageSize.pageHeight - this.options.heightOfBorders) + 'px'
          });
          this.element.setStyle({
            width: pageSize.pageWidth + 'px', 
            height: pageSize.pageHeight + 'px',
            top:'0px',
            left:'0px'
          });
        }
      }.bind(this));
    }

    // Checking to see if window is initially visible
    if( this.options.closable ){
      Element.observe($(this.element.id+'_CLOSER'), 'click', function(){
        if( !this._closingInProgress ){
          this._closingInProgress = true;
          Control.callControlMethod.bind(this)('CloseMethod', [], function(retVal){
             // DO NOTHING, Server dispatches to setVisible method...!!
            delete this._closingInProgress;
          }.bind(this), this.element.id.substr(0,this.element.id.length - 4));
        }
      }.bind(this));
    }

    // Checking to see if window is resizable
    if( this.options.resizable == true ){
      this.addResizers();
    }
  },

  setWidth: function(value){
    this.options.width = value;
    this.element.setStyle({
      width: (parseInt(this.options.width, 10) + this.options.widthOfBorders) + 'px'
    });
    var inner = $(this.element.id.substr(0,this.element.id.length-4));
    inner.setStyle({
      width: parseInt(this.options.width, 10) + 'px'
    });
    return this;
  },

  setHeight: function(value){
    this.options.height = value;
    this.element.setStyle({
      height: (parseInt(this.options.height, 10) + this.options.heightOfBorders) + 'px'
    });
    var inner = $(this.element.id.substr(0,this.element.id.length-4));
    inner.setStyle({
      height: parseInt(this.options.height, 10) + 'px'
    });
    return this;
  },

  addResizers: function(){
    var resizer = $(this.element.id+'_RESIZER');
    Element.addClassName(resizer, this.options.className + '_sizer');
    Element.observe(resizer, 'mousedown', this._onResizerMouseDown.bindAsEventListener(this));
    Element.observe(document, 'mouseup', this._onResizerMouseUp.bindAsEventListener(this));
    Element.observe(document, 'mousemove', this._onResizerMouseMove.bindAsEventListener(this));
  },

  _onResizerMouseDown: function(evt){
    this._x = Event.pointerX(evt);
    this._y = Event.pointerY(evt);
    if( document.body.style.mozUserSelect ){
      this._oldMozSelect = document.body.style.mozUserSelect;
      document.body.style.mozUserSelect = 'none';
    } else {
      this._stopSelect = function(evt){Event.stop(evt);}.bindAsEventListener(this);
      Element.observe(document.body, 'selectstart', this._stopSelect);
    }
  },

  _onResizerMouseUp: function(evt){
    delete this._x;
    delete this._y;
    if( document.body.style.mozUserSelect ){
      document.body.style.mozUserSelect = this._oldMozSelect;
    } else {
      Element.stopObserving(document.body, 'selectstart', this._stopSelect);
    }
  },

  _onResizerMouseMove: function(evt){
    if( this._x && this._y ){

      // User are holding down mouse button...!!
      var oldX = this._x;
      var oldY = this._y;
      this._x = Event.pointerX(evt);
      this._y = Event.pointerY(evt);
      var deltaX = (this._x - oldX);
      var deltaY = (this._y - oldY);

      // Setting height/width of ALL window
      var newWidth = parseInt(this.element.style.width,10) + deltaX;
      var newHeight = parseInt(this.element.style.height,10) + deltaY;

      // Checking to see if size is less than minimum accepted size
      if (newWidth < this.options.minWidth)
        newWidth = this.options.minWidth;
      if (newHeight < this.options.minHeight)
        newHeight = this.options.minHeight;

      // Setting the new size
      this.element.setStyle({
        width: newWidth+'px', 
        height: newHeight+'px'
      });

      // Setting height/width of just the container div WITHIN window
      var inner = $(this.element.id.substr(0,this.element.id.length-4));
      var newInnerWidth = parseInt(inner.style.width,10) + deltaX;
      var newInnerHeight = parseInt(inner.style.height,10) + deltaY;

      // Checking to see if size is less than minimum accepted size
      if (newInnerWidth + this.options.widthOfBorders < this.options.minWidth)
        newInnerWidth = this.options.minWidth - this.options.widthOfBorders;
      if (newInnerHeight + this.options.heightOfBorders < this.options.minHeight)
        newInnerHeight = this.options.minHeight - this.options.heightOfBorders;

      // Setting the new size
      inner.setStyle({
        width: newInnerWidth+'px', 
        height: newInnerHeight+'px'
      });
    }
  },

  setVisible: function(value){
    if( value == true ){

      // Making window appear ON TOP of any other visible windows...!!
      var zIndex = 500;
      if( WebControl.Window._visibleWindows.length > 0 ){
        zIndex = WebControl.Window._visibleWindows[WebControl.Window._visibleWindows.length - 1].element.style.zIndex + 2;
      }

      WebControl.Window._visibleWindows.push(this);

      Element.show(this.element);
      Element.setStyle(this.element, {zIndex:(zIndex + 1)});

      // Checking to see if we need to obscure the rest of the surface...!!
      if( this.options.modal == true ){
        this.obscurer = Builder.node('div', {
          style:'z-index:'+(zIndex)+';'+
            'background-color:#ccf;'+
            'position:absolute;'
        });
        var size = this.getPageSize();
        var scroll = this._getWindowScroll(window);

        // We should probably try to FIX this, but for now we set the obscurer to fill the EXACT space of the viewport since IE will mess with
        // the opacity if it becomes TOO big and we therefore CAN'T set its size to the size of the page...
        this.obscurer.style.height = (size.windowHeight+'px');
        this.obscurer.style.width = (size.windowWidth+'px');
        this.obscurer.style.left = (scroll.left+'px');
        this.obscurer.style.top = (scroll.top+'px');
        this.obscurer.style.display = 'block';
        Element.setOpacity(this.obscurer, 0.6);
        document.body.appendChild(this.obscurer);

        this.pageSize = null;
        this._onScroll = function(evt){
          var scroll = this._getWindowScroll(window);
          this.obscurer.style.left = (scroll.left+'px');
          this.obscurer.style.top = (scroll.top+'px');
          if( this.options.autoCenter == true )
            this.center();
        }.bindAsEventListener(this);
        Event.observe(window, 'scroll', this._onScroll);

        this._onResize = function(evt){
          var size = this.getPageSize();

          // IE sends out some crapy events for this event
          if (this.pageSize && this.pageSize.pageWidth == size.windowWidth && this.pageSize.pageHeight == size.windowHeight)
            return;
          this.pageSize = size;

          this.obscurer.style.height = (size.windowHeight+'px');
          this.obscurer.style.width = (size.windowWidth+'px');
          if( this.options.autoCenter == true )
            this.center();
        }.bindAsEventListener(this);
        Event.observe(window, 'resize', this._onResize);
      }

      // Checking to see if we need to do some default styling...
      if( this.options.className == null || this.options.className == '' ){
        var mainId = this.getMainElement().id;

        // Top table
        this.element.style.backgroundColor = '#eee';
        this.element.style.border = 'solid 1px Black';
        var topTbl = $(mainId+'_TOP_TABLE');
        topTbl.style.width = '100%';
        topTbl.style.backgroundColor='#ccf';
        var nw = $(mainId+'_NW');
        nw.style.width = '5px';
        var n = $(mainId+'_DIV_HANDLE');
        n.style.width = '100%';
        var ne = $(mainId+'_NE');
        ne.style.width = '5px';

        // Closer
        var closer = $(mainId+'_DIV_CLOSER');
        if(closer){
          closer.innerHTML = 'X';
          closer.style.position = 'absolute';
          closer.style.left = '25px';
        }

        // minimizer
        var mini = $(mainId+'_DIV_MINIMIZER');
        if(mini){
          mini.innerHTML = '_';
          mini.style.position = 'absolute';
          mini.style.left = '40px';
        }

        // maxi
        var maxi = $(mainId+'_DIV_MAXIMIZER');
        if(maxi){
          maxi.innerHTML = 'O';
          maxi.style.position = 'absolute';
          maxi.style.left = '55px';
        }

        // Content table
        var content = $(mainId+'_CONTENT_TBL');
        content.style.width='100%';
        //content.style.height='100%';
      }
    } else {

      // Stopping all event listeners...
      Event.stopObserving(window, 'scroll', this._onScroll);
      Event.stopObserving(window, 'resize', this._onResize);

      // Making sure control and child controls is destroyed...
      this.destroy();

      var idx = 0;
      WebControl.Window._visibleWindows.each(function(wnd){
        if( wnd == this )
          throw $break;
        idx += 1;
      }.bind(this));
      WebControl.Window._visibleWindows.splice(idx, 1);
      Element.hide(this.element);
      if( this.obscurer ){
        this.obscurer.parentNode.removeChild(this.obscurer);
        delete this.obscurer;
      }
    }
  },

  getMainElement: function(){
    if( !this._mainElement )
      this._mainElement = $(this.element.id.substr(0,this.element.id.length-4));
    return this._mainElement;
  },

  destroy: function(){

    // Unregistering draggable...
    if( this.draggable )
      this.draggable.destroy();

    // Destroying all CHILDREN controls
    this.destroyChildrenControls();

    // Calling Object.destroy implementation...
    this._destroyImpl();
  },

  center: function(){
    var pageSize = this.getPageSize();
    var scroll = this._getWindowScroll(window);
    var left = Math.max((pageSize.windowWidth / 2) - (parseInt(this.options.width, 10) / 2) + scroll.left, 0);
    var top = Math.max((pageSize.windowHeight / 2) - (parseInt(this.options.height, 10) / 2) + scroll.top, 0);
    this.setLocation(left, top);
  },

  setLocation: function(x, y){
    if( typeof x == 'number' )
      this.element.setStyle({left: (x + 'px')});
    else
      this.element.setStyle({left: x});
    if( typeof y == 'number' )
      this.element.setStyle({top: (y + 'px')});
    else
      this.element.setStyle({top: y});
  },

  // From script aculous...!!
  _getWindowScroll: function(w) {
    var T, L, W, H;
    with (w.document) {
      if (w.document.documentElement && documentElement.scrollTop != 'undefined') {
        T = documentElement.scrollTop;
        L = documentElement.scrollLeft;
      } else if (w.document.body) {
        T = body.scrollTop;
        L = body.scrollLeft;
      }
      if (w.innerWidth) {
        W = w.innerWidth;
        H = w.innerHeight;
      } else if (w.document.documentElement && documentElement.clientWidth) {
        W = documentElement.clientWidth;
        H = documentElement.clientHeight;
      } else {
        W = body.offsetWidth;
        H = body.offsetHeight
      }
    }
    return { top: T, left: L, width: W, height: H };
  },

  getPageSize: function(){

  	var xScroll;
  	var yScroll;
  	if (window.innerHeight && window.scrollMaxY) {	
  		xScroll = document.body.scrollWidth;
  		yScroll = window.innerHeight + window.scrollMaxY;
  	} else if (document.body.scrollHeight > document.body.offsetHeight){
  		xScroll = document.body.scrollWidth;
  		yScroll = document.body.scrollHeight;
  	} else {
  		xScroll = document.body.offsetWidth;
  		yScroll = document.body.offsetHeight;
  	}

  	var windowWidth;
  	var windowHeight;
  	if (self.innerHeight) {
  		windowWidth = self.innerWidth;
  		windowHeight = self.innerHeight;
  	} else if (document.documentElement && document.documentElement.clientHeight) {
  		windowWidth = document.documentElement.clientWidth;
  		windowHeight = document.documentElement.clientHeight;
  	} else if (document.body) {
  		windowWidth = document.body.clientWidth;
  		windowHeight = document.body.clientHeight;
  	}	

  	var pageHeight;
  	var pageWidth;
  	if(yScroll < windowHeight){
  		pageHeight = windowHeight;
  	} else { 
  		pageHeight = yScroll;
  	}
  	if(xScroll < windowWidth){
  		pageWidth = windowWidth;
  	} else {
  		pageWidth = xScroll;
  	}
  	return {
  	  pageWidth: pageWidth, 
  	  pageHeight: pageHeight, 
  	  windowWidth: windowWidth, 
  	  windowHeight: windowHeight
  	};
  },

  _getElementPostValue: function(){
    return '';
  }
});

