

/*---------------------------------------------------------------------------*
 * -- zArray
 *---------------------------------------------------------------------------*
 *  List of key/value pairs..don't ask me why.
 *---------------------------------------------------------------------------*/

function zArray( ) {
  this.ma_array = new Array();
}

zArray.prototype.getLength = function() { return this.ma_array.length; };
zArray.prototype.shift = function() { return this.ma_array.shift(); };
zArray.prototype.push = function( io_object ) { this.ma_array.push( io_object ); };
zArray.prototype.sort = function( if_function ) { this.ma_array = this.ma_array.sort( if_function ); };
zArray.prototype.toArray = function() { return this.ma_array; };

zArray.prototype.insert = function( io_value, ib_noDuplicates ) {
  if( ib_noDuplicates == true && this.contains( io_value ) == true ) {
    return;
  } else {
    this.ma_array.push( io_value );
  }
};
zArray.prototype.contains = function( io_value ) { 
  for( var i = 0; i < this.ma_array.length; i++ ) {
    if( this.ma_array[i].equals( io_value ) ) { return true; }
  }
  return false;
};
zArray.prototype.notIn = function( ia_array ) {
  var la_result = new zArray();
  for( var i = 0; i < this.ma_array.length; i++ ) {
    if( ia_array.contains( this.ma_array[i] ) == false ) {
      la_result.push( this.ma_array[i] );
    }
  }
  return la_result;
};

zArray.prototype.inArray = function( ia_array ) {
  var la_result = new zArray();
  for( var i = 0; i < this.ma_array.length; i++ ) {
    if( ia_array.contains( this.ma_array[i] ) == true ) {
      la_result.push( this.ma_array[i] );
    }
  }
  return la_result;
};
zArray.prototype.getIndex = function( in_index ) { return this.ma_array[in_index]; };
zArray.prototype.getIterator = function() { return new zArrayIterator( this ); };


function zArrayIterator( io_zArray ) {
  this.mn_nextIndex = 0;
  this.mo_zArray = io_zArray;
}
zArrayIterator.prototype.hasNext = function() { return ( this.mn_nextIndex <= ( this.mo_zArray.getLength() - 1 ) ); };
zArrayIterator.prototype.getNext = function() { return ( this.mo_zArray.getIndex( this.mn_nextIndex++ ) ); };
zArrayIterator.prototype.reset = function() { this.mn_nextIndex = 0; };



function zSortedList() {}
zSortedList.prototype = new zArray();

zSortedList.prototype.contains = function( io_value ) { 
  return ( this.search( io_value ) != -1 );
};
zSortedList.prototype.insert = function( io_value, ib_noDuplicates ) {
  if( ib_noDuplicates && this.binarySeach( io_value ) != -1 ) {
    return;
  } else {
    this.splice( this.binarySearch( io_value ), 1, io_value );
  }
};
zSortedList.prototype.search = function( io_value, ib_insert ) {
  var h = this.ma_array.length, l = -1, m;
  while(h - l > 1)
      if( this.ma_array[m = h + l >> 1].compareTo(io_value) < 0 ) l = m;
      else h = m;
  return !this.ma_array[h].equals( io_value ) ? ib_insert ? h : -1 : h;
};



/*---------------------------------------------------------------------------*
 * -- zList
 *---------------------------------------------------------------------------*
 *  List of key/value pairs..don't ask me why.
 *---------------------------------------------------------------------------*/

function zList() {}

zList.prototype = new Array();

zList.prototype.insert = function( iv_key, iv_value ) {
  if( this.containsKey( iv_key ) ) {
    throw new Error( 'List already contains key: ' + iv_key );
  }
  this.push( { key : iv_key, value : iv_value } );
};

zList.prototype.remove = function( iv_key ) {
  if( !this.containsKey( iv_key ) ) {
    throw new Error( 'List doesn\'t contain key: ' + iv_key );
  }
  this.splice( this.indexOf( iv_key, false ), 1 );
};

zList.prototype.containsKey = function( iv_key ) {
  return ( this.indexOf( iv_key, false ) >= 0 );
};

// -- returns offset of a given value, or the location where it should be inserted
zList.prototype.indexOf = function( iv_key, ib_shouldBe ) {
  for( var i = 0; i < this.length; i++ ) {
    if( this[i].key == iv_key ) return i;
  }
  return -1;
};

zList.prototype.getValue = function( iv_key ) {
  var ln_index = this.indexOf( iv_key, false );
  if( ln_index >= 0 ) { return this[ln_index].value; }
  else { return null; }
};

zList.prototype.getKeys = function() { return this.getArray( 'key' ); };
zList.prototype.getValues = function() { return this.getArray( 'value' ); };

zList.prototype.getArray = function( is_prop ) {
  var la_array = new Array();
  for( var i = 0; i < this.length; i++ ) {
    la_array.push( this[i][is_prop] );
  }
  return la_array;
};

zList.prototype.getLength = function() { return this.length; }
zList.prototype.removeLast = function() { return this.shift(); }

