// Copyright (c) 2007, Michael Schuerig, michael@schuerig.de
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

if (!window.Layout) {
  var Layout = {};
}

Layout.ThresholdList = function(array) {
  return Object.extend($A(array), Layout.ThresholdList.ArrayExt);
};

Layout.ThresholdList.ArrayExt = {
  findBelow: function(dim) {
    return this.detect(function(thres) {
      return thres[0] <= dim;
    })[1];
  }
};

Object.extend(Layout, {
  Version: '0.2.0',
  
  INITIALIZE: 0,
  WINDOW_SIZE_CHANGED: 1,
  FONT_SIZE_CHANGED: 2,

  horzThresholds: Layout.ThresholdList([
    [ 72, 'large' ],
    [  0, 'small' ]
  ]),
  vertThresholds: Layout.ThresholdList([
    [ 40, 'tall'  ],
    [  0, 'flat'  ]
  ]),
  current: $A(),
  
  observers: [],

  // Initialize window and font size-based layout switching.
  //
  // Depending on the relative size of the view, the class attribute of
  // the HTML body element is set.
  // The relative width and height is determined by dividing the absolute
  // dimensions (px) by the current font size.
  // The class names applied to the body element are determined by
  // lists of horizontal and vertical thresholds that map relative 
  // width/height to a class name.
  // These list must be in descending order and the last element should
  // be for width/height 0. See the defaults above for an example.
  //
  // Options:
  // * horzThresholds
  // * vertThresholds
  // * ignoreResize - ignore window resizing; default false
  // * observeFontSize - watch out for changes of the font size; default false
  // * resizeCheckInterval - interval (in milliseconds) for checking for font size changes; default 500
  initialize: function(options) {
    options = options || {};
    if (options.horzThresholds) {
      this.setHorzThresholds(options.horzThresholds);
    }
    if (options.vertThresholds) {
      this.setVertThresholds(options.vertThresholds);
    }
    this.currSize = this.fontSize();
    this.options = options;
    this.switchLayout(Layout.INITIALIZE);
    this.enable();
  },
  
  enable: function() {
    if (this.active) {
      return;
    }
    if (!this.options.ignoreResize) {
      Event.observe(window, 'resize', this.onResize.bind(this));
    }
    if (this.options.observeFontSize) {
      this.fontSizeObserver = setInterval(this.detectFontSizeChange.bind(this),
        this.options.resizeCheckInterval || 500)
    }
    this.active = true;
  },

  disable: function() {
    if (!this.active) {
      return;
    }
    if (!this.options.ignoreResize) {
      Event.stopObserving(window, 'resize', this.onResize);
    }
    if (this.options.observeFontSize && this.fontSizeObserver) {
      clearInterval(this.fontSizeObserver);
      this.fontSizeObserver = null;
    }
    this.active = false;
  },

  setHorzThresholds: function(thresholds) {
    this.horzThresholds = Layout.ThresholdList(thresholds);
  },
  
  setVertThresholds: function(thresholds) {
    this.vertThresholds = Layout.ThresholdList(thresholds);
  },
  
  currentLayout: function() {
    return this.current;
  },
  
  switchLayout: function(why, newLayout) {
    this.current.each(function(layout) {
      Element.removeClassName(document.body, layout);
    });
    this.current = null;
    if (newLayout) {
      if (typeof newLayout == 'string') {
        this.current = $w(newLayout)
      } else if (newLayout instanceof Array) {
        this.current = $(newLayout);
      }
    }
    if (!this.current) {
      this.current = this.findLayout();
    }
    this.current.each(function(layout) {
      Element.addClassName(document.body, layout);
    });
    this.notifyObservers(why);
  },
  
  notifyObservers: function(why) {
    var len = this.observers.length;
    for (var i = 0; i < len; i++) {
      this.observers[i](why);
    }
  },
  
  addObserver: function(f) {
    this.observers.push(f);
  },
  
  findLayout: function(width, height) {
    var dims = this.relativeDimensions();
    width = width || dims[0];
    height = height || dims[1];
    return $A([this.horzThresholds.findBelow(width), 
      this.vertThresholds.findBelow(height)]);
  },
  
  relativeDimensions: function() {
    var fontSize = this.fontSize();
    var dims = this.dimensions();
    return [Math.round(dims[0] / fontSize), Math.round(dims[1] / fontSize)];
  },
  
  dimensions: function() {
    if (window.innerWidth) {
      return [window.innerWidth, window.innerHeight];
    }	
    else if (document.documentElement && document.documentElement.clientWidth != 0) {
      return [document.documentElement.clientWidth, document.documentElement.clientHeight];
    }
		else if (document.body) {
		  return [document.body.clientWidth, document.body.clientHeight];
		}
    return [0, 0];
  },
	
	fontSize: function() {
	  return parseInt(Element.getStyle(document.body, 'font-size'));
	},
	
	onResize: function() {
    //console.debug('resize'); 
	  this.switchLayout(Layout.WINDOW_SIZE_CHANGED);
	},

  detectFontSizeChange: function() {
    var newSize = this.fontSize();
    if (newSize != this.currSize) {
      //console.debug('Font size changed from ', this.currSize, ' to ', newSize);
      this.switchLayout(Layout.FONT_SIZE_CHANGED);
    }
    this.currSize = newSize;
  }
});


