(function(){

var columnator = window.columnator = function( containerId, cols, gutterWidth ) {
  return this instanceof columnator ?
    this.init( containerId, cols, gutterWidth ) :
    new columnator( containerId, cols, gutterWidth );
};

columnator.fn = columnator.prototype = {
  version: "V1.0",
  container: null,
  containerId: "",
  cols: [ 350, 302 ],
  gutterWidth: 16,

  sumTo: function( a, to, ind ) {
    var sum = 0;
    for( var i = 0 ; i < to && i < a.length ; i++ ) sum += a[i][ind];
    return sum;
  },

  sumFrom: function( a, from, ind ) {
    var sum = 0;
    for( var i = from ; i < a.length ; i++ ) sum += a[i][ind];
    return sum;
  },

  toNum: function( val ) {
    return parseInt( "0" + val, 10 );
  },

  fullHeight: function( elem ) {
    var elemHeight = elem.height();

    elemHeight += this.toNum( elem.css( "marginTop" ) );
    elemHeight += this.toNum( elem.css( "marginBottom" ) );
    elemHeight += this.toNum( elem.css( "borderTopWidth" ) );
    elemHeight += this.toNum( elem.css( "borderBottomWidth" ) );
    elemHeight += this.toNum( elem.css( "paddingTop" ) );
    elemHeight += this.toNum( elem.css( "paddingBottom" ) );

    return elemHeight;
  },

  debug: function( str ) {
    var debug = $("#debug");

    if( debug.length == 0 )
    {
      debug = $('<div id="debug"></div>' ).appendTo( $("body") );
    }

    debug.html( debug.html() + str + "<br />" );
  },

  layout: function( cols, gutterWidth ) {
    this.cols        = ( ( typeof( cols        ) != "undefined" ) ? cols        : this.cols        );
    this.gutterWidth = ( ( typeof( gutterWidth ) != "undefined" ) ? gutterWidth : this.gutterWidth );

    this.redraw();
  },

  redraw: function() {
    var minHeight    = 0;
    var colHeight    = 0;
    var leftHeight   = 0;
    var rightHeight  = 0;
    var colWidth     = Math.floor( ( this.container.width() - this.gutterWidth ) / 2.0 );
    var blockHeights = new Array( this.children.length );

    var leftCol  = $('<div id="' + this.containerId + 'L" style="width:' + this.cols[0] + 'px; float:left;"></div>').appendTo( this.container );
    var rightCol = $('<div id="' + this.containerId + 'R" style="width:' + this.cols[1] + 'px; float:left; margin-left:' + this.gutterWidth + 'px"></div>').appendTo( this.container );
    $('<div style="height:0px;line-height:0px;clear:left"></div>').appendTo( this.container );

    for( var i = 0 ; i < this.children.length ; i++ )
    {
      blockHeights[i] = new Array( 2 );

      $(this.children[i]).appendTo( leftCol );
      blockHeights[i][0] = this.fullHeight( $(this.children[i]) );

      $(this.children[i]).prependTo( rightCol );
      blockHeights[i][1] = this.fullHeight( $(this.children[i]) );

      minHeight += ( ( blockHeights[i][0] > blockHeights[i][1] ) ? blockHeights[i][0] : blockHeights[i][1] );
    }

    var matchPos;
    var heightDiff;

    for( var i = 0 ; i <= blockHeights.length ; i++ )
    {
      heightDiff = Math.abs( this.sumTo( blockHeights, i, 0 ) - this.sumFrom( blockHeights, i, 1 ) );

      if( heightDiff < minHeight )
      {
        minHeight = heightDiff;
        matchPos = i;
      }
    }

    for( var i = 0 ; i < this.children.length ; i++ )
    {
      $(this.children[i]).appendTo( ( i < matchPos ) ? leftCol : rightCol );
    }
  },

  init: function( containerId, cols, gutterWidth ) {
    this.containerId = containerId;
    this.cols        = ( ( typeof( cols        ) != "undefined" ) ? cols        : this.cols        );
    this.gutterWidth = ( ( typeof( gutterWidth ) != "undefined" ) ? gutterWidth : this.gutterWidth );

    this.container = $("#" + containerId);
    this.children  = this.container.children();

    this.redraw();
  }
};
})();
