//
// CompositeLoader
//

function CompositeLoader( loaders )
{
  this.loaders    = loaders;
  this.elements   = [];
  this.incomplete = 0;
  this.pending    = false;
  this.loaded     = new Event();
}

CompositeLoader.prototype = 
{
  load: function()
  {
    var i;
    var loader;
    
    if ( !this.pending )
    {
      if ( this.loaders.length < 1 )
      {
        this.onLoaded();
      }
      else
      {
        this.pending = true;
        this.incomplete = this.loaders.length;

        for ( i = 0; i < this.loaders.length; ++i )
        {
          loader = this.loaders[ i ];
          loader.loaded.attach( this.loaderLoaded.bind( this ) );
          loader.load();
        }
      }
    }
  },
  
  getElements: function()
  {
    return this.elements;
  },
  
  loaderLoaded: function()
  {
    if ( --this.incomplete == 0 )
    {
      this.onLoaded();
    }
  },
  
  onLoaded: function()
  {
    var i, j;
    var loadedElements;
    
    for ( i = 0; i < this.loaders.length; ++i )
    {
      loadedElements = this.loaders[ i ].getElements();
      
      for ( j = 0; j < loadedElements.length; ++j )
      {
        this.elements.push( loadedElements[ j ] );
      }
    }
  
    this.pending = false;
    this.loaded.fire( this );
  }
};

//
// ImageLoader
//

function ImageLoader( url, options )
{
  this.url = url;
  this.image = null;
  this.loaded = new Event();
  this.pending = false;
  this.img = null;
  
  options = options || {};
  this.context = options.context || document;
}  

ImageLoader.prototype =
{
  load: function()
  {
    if ( !this.pending )
    {
      this.pending = true;
      
      var image = this.image = new Image();
      image.onload = this.onImageLoaded.bind( this );
      
      image.src = this.url;
    }
  },
  
  getElements: function()
  {
    return [ this.img ];
  },
  
  getElement: function()
  {
    return this.img;
  },
  
  onImageLoaded: function()
  {
    this.pending = false;
    this.createImg(); 
    this.loaded.fire( this );
  },
  
  createImg: function()
  {
    this.img = this.context.createElement( "img" );
    this.img.src = this.image.src;
    this.img.width = this.image.width;
    this.img.height = this.image.height;
  }
};

//
// MultipleImageLoader
//

function MultipleImageLoader( urls, options )
{
  this.loaded = new Event();
  this.loader = null;

  var i;
  var loaders = [];
  
  for ( i = 0; i < urls.length; ++i )
  {
    loaders.push( new ImageLoader( urls[ i ], options ) );
  }
  
  this.loader = new CompositeLoader( loaders );
  this.loader.loaded.attach( this.onCompositeLoaderLoaded.bind( this ) );
}

MultipleImageLoader.prototype =
{
  load: function()
  {
    this.loader.load();
  },
  
  getElements: function()
  {
    return this.loader.getElements();
  },
  
  onCompositeLoaderLoaded: function()
  {
    this.loaded.fire( this );
  }
};

//
// LinkedImageLoader
//

function LinkedImageLoader( imageUrl, linkUrl, options )
{
  options       = options || {};
  this.context  = options.context || document;
  this.pending  = false;
  this.loaded   = new Event();
  this.linkUrl  = linkUrl;
  
  this.imageLoader = new ImageLoader( imageUrl, options );
  this.imageLoader.loaded.attach( this.onImageLoaderLoaded.bind( this ) );
}

LinkedImageLoader.prototype =
{
  load: function()
  {
    this.imageLoader.load();
  },
  
  onImageLoaderLoaded: function()
  {
    this.createElement();
    this.loaded.fire( this );
  },
  
  getElements: function()
  {
    return [ this.element ];
  },
  
  getElement: function()
  {
    return this.element;
  },
  
  createElement: function()
  {
    var img = this.imageLoader.getElement();

    var div = this.context.createElement( "div" );
    div.style.width = new Length( img.width ).toString();
    div.style.height = new Length( img.height ).toString();

    var a = this.context.createElement( "a" );
    a.href = this.linkUrl;
    
    a.appendChild( img );
    div.appendChild( a );
    
    this.element = div;
  }
};

//
// MultipleLinkedImageLoader
//

function MultipleLinkedImageLoader( imageUrls, linkUrls, options )
{
  this.loaded = new Event();
  this.loader = null;

  var i;
  var loaders = [];
  
  for ( i = 0; i < imageUrls.length; ++i )
  {
    loaders.push( new LinkedImageLoader( imageUrls[ i ], linkUrls[ i ], options ) );
  }
  
  this.loader = new CompositeLoader( loaders );
  this.loader.loaded.attach( this.onCompositeLoaderLoaded.bind( this ) );
}

MultipleLinkedImageLoader.prototype =
{
  load: function()
  {
    this.loader.load();
  },
  
  getElements: function()
  {
    return this.loader.getElements();
  },
  
  onCompositeLoaderLoaded: function()
  {
    this.loaded.fire( this );
  }
};