var MetaImageSearcher = Class.create({
  initialize: function(options) {
    // pass in uniqueStr for function callback global. uniqueStr must already be a global object e.g. ImageSearcher
    options = Object.extend({
      uniqueStr: 'MetaImageSearcher',
      engines:['photobucket', 'google', 'live', 'youtube', 'flickr'],
      defaultEngine: 'photobucket'
    }, options || {});
    this.options = options;
    this.updateFuncIndex = -1;
    this.page = 0;
    this.plugins = options.engines.collect(function(engine) {
      return new window[engine.capitalize()+'MediaPlugin']();
    });
    this.selectEngine(options.defaultEngine);
  },
  selectEngine: function(engineName) {
    engineName = engineName.toLowerCase();
    this.selectedPlugin = this.plugins.find(function(plugin) {
      return plugin.getName() == engineName;}
    );
    if (!this.selectedPlugin) {this.selectedPlugin = this.plugins[0];}
  },
  setSuccess: function(successFunc) {
    this.success = successFunc;
  },
  setError: function(errorFunc) {
    this.error = errorFunc;
  },
  search: function(searchOptions) {
    if (searchOptions.plugin) {this.selectEngine(searchOptions.plugin);}
    searchOptions = Object.extend({success:this.success, error:this.error}, searchOptions);
    this.page = searchOptions.page || 0;
    this.lastSearch = this.selectedPlugin.search(this, searchOptions);
    this.prevSearchOptions = searchOptions;
  },
  nextPage: function() {
    ++this.page;
    this.gotoPage();
  },
  previousPage: function() {
    --this.page;
    this.gotoPage();
  },
  getPage: function() {
    return this.page;
  },
  noMorePages: function() {
    return this.lastSearch && this.page == 7;
  },
  gotoPage: function() {
    if (this.lastSearch) {
      this.lastSearch.gotoPage(this.page);
    }
    else {
      var searchOptions = this.prevSearchOptions;
      searchOptions.page = this.page;
      this.search(searchOptions);
    }
  },
  getCurrentEngine: function() {
    return this.selectedPlugin.getName();
  },
  getStaticUpdateFunc: function(pluginFunc) {
    var uniqueFuncStr = 'updateFunc' + (++this.updateFuncIndex);
    var uniqueStr = this.options.uniqueStr;
    window[uniqueStr][uniqueFuncStr] = pluginFunc;
    return uniqueStr + '.' + uniqueFuncStr;
  }
});

var JsonpMediaPlugin = Class.create({
  initialize: function(options) {
    this.options = options;
    this.baseUrl = options.baseUrl;
    this.callbackKey = options.callbackKey;
    this.pageKey = options.pageKey;
    this.offsetKey = options.offsetKey;
    this.perPageKey = options.perPageKey;
    this.perPage = options.perPage || 8;
  },
  search: function(meta, searchOptions) {
    var staticUpdateFunc = meta.getStaticUpdateFunc(this.updateFunc.bind(this, searchOptions));
    var searchUrl = this.baseUrl + encodeURIComponent(searchOptions.query);
    searchUrl += '&' + this.callbackKey + '=' + encodeURIComponent(staticUpdateFunc);
    searchUrl += '&' + this.perPageKey + '=' + this.perPage;
    if (searchOptions.page && this.pageKey) {searchUrl += '&' + this.pageKey + '=' + (searchOptions.page+1);}
    if (searchOptions.page && this.offsetKey) {
      searchUrl += '&' + this.offsetKey + '=' + this.perPage*searchOptions.page;
    }
    appendScript.defer(searchUrl);
  },
  updateFunc: function(results) {
    alert('virtual JsonpMediaPlugin called - needs implementation');
  },
  getName: function() {
    alert('virtual getName method called - needs implementation');
  }
});


var FlickrMediaPlugin = Class.create(JsonpMediaPlugin, {
  initialize: function($super, options) {
    options = Object.extend({
      baseUrl:"http://api.flickr.com/services/rest/?method=flickr.photos.search&api_key=b3c10aaffb08eccf9b3afffa2c66066f&"
      + "sort=interestingness-desc&format=json&license=4,5,6&text=",
      callbackKey:"jsoncallback",
      pageKey:'page',
      perPageKey: 'per_page'}, options || {});
    $super(options);
  },
  updateFunc: function(searchOptions, results) {
    var errMsg = null;
    try {
      if (results.stat == 'ok') {
        var images = $A();
        results.photos.photo.each(function(photo) {
          var imgUrl = 'http://farm' + photo.farm + 
            '.static.flickr.com/'+photo.server+'/'+photo.id+'_'+photo.secret+'_m.jpg';
          var thumbUrl = 'http://farm' + photo.farm + 
            '.static.flickr.com/'+photo.server+'/'+photo.id+'_'+photo.secret+'_m.jpg';
          var imgInfo = new ImageInfo(photo.title, imgUrl, thumbUrl);
          imgInfo.engine = 'flickr';
          imgInfo.creditsLink = 'http://flickr.com/photos/' + photo.owner + '/' + photo.id;
          imgInfo.query = searchOptions.query;
          images.push(imgInfo);
        });
        if (searchOptions.success) {searchOptions.success(images);}
      }
      else {
        errMsg = results.message;
      }
    }
    catch(e) {
      errMsg = e;
    }
    if (errMsg && searchOptions.error) {searchOptions.error(errMsg);}
  },
  getName: function() {
    return 'flickr';
  }
});

var LiveMediaPlugin = Class.create(JsonpMediaPlugin, {
  initialize: function($super, options) {
    options = Object.extend({
      baseUrl:"http://api.search.live.net/json.aspx?AppId=F49E8B6ADE036032B7D27B226B4EFE2B34E4B409&Market=en-US&" +
      "Version=2.0&Sources=Image&JsonType=callback&Adult=Strict&Query=",
      callbackKey: "JsonCallback",
      offsetKey: "Image.Offset",
      perPageKey: "Image.Count"
    }, options || {});
    $super(options);
  },
  updateFunc: function(searchOptions, response) {
    var errors = response.SearchResponse.Errors;
    if (errors) {
      if (searchOptions.error) {searchOptions.error(errors);}
    }
    else {
      var results = response.SearchResponse.Image.Results || [];
      var images = $A();
      results.each(function(result) {
        var imgInfo = new ImageInfo(result.Title, result.MediaUrl, result.MediaUrl, result.Width, result.Height);
        imgInfo.engine = 'live';
        imgInfo.creditsLink = result.Url;
        imgInfo.query = searchOptions.query;
        imgInfo.contentType = result.ContentType;
        imgInfo.fileSize = result.FileSize;
        images.push(imgInfo);
      });
      if (searchOptions.success) {searchOptions.success(images);}
    }
  },
  getName: function() {
    return 'live';
  }
});
      
var YoutubeMediaPlugin = Class.create(JsonpMediaPlugin, {
  initialize: function($super, options) {
    options = Object.extend({
      baseUrl:"http://gdata.youtube.com/feeds/videos?alt=json-in-script&format=5&q=",
      callbackKey: 'callback',
      offsetKey: 'start-index',
      perPageKey: 'max-results'
    }, options || {});
    $super(options);
  },
  updateFunc: function(searchOptions, response) {
    try {
      var results = response.feed.entry || [];
      var videos = results.collect(function(result) {
        return new VideoInfo(result.title.$t, result.media$group.media$content[0].url, searchOptions.query);
      });
      if (searchOptions.success) {searchOptions.success(videos);}
    }
    catch(e) {
      if (searchOptions.error) {searchOptions.error(e);}
    }
  },
  getName: function() {
    return 'youtube';
  }
});
        
      
var GoogleMediaPlugin = Class.create({
  initialize: function(options) {
    this.options = options || {};
  },
  getName: function() {
    return 'google';
  },
  search: function(meta, searchOptions) {
    var gSearch = new google.search.ImageSearch();
    gSearch.setResultSetSize(google.search.Search.LARGE_RESULTSET);
    gSearch.setRestriction(google.search.Search.RESTRICT_SAFESEARCH, google.search.Search.SAFESEARCH_STRICT);
    gSearch.setSearchCompleteCallback(this, this.updateFunc, [gSearch, searchOptions]);
    this.setCustomRestrictions(gSearch);
    gSearch.execute(searchOptions.query);
    return gSearch;
  },
  setCustomRestrictions: function(gSearch) {},
  updateFunc: function(gSearch, searchOptions) {
    var images = $A();
    window.zz = gSearch.results;
    gSearch.results.each(function(result) {
      imgInfo = new ImageInfo(result.titleNoFormatting, result.unescapedUrl, result.unescapedUrl,
        result.width, result.height);
      imgInfo.creditsLink = result.originalContextUrl;
      imgInfo.engine = 'Google';
      imgInfo.context = result.content;
      imgInfo.query = searchOptions.query;
      images.push(imgInfo);
    });
    if (searchOptions.success) {searchOptions.success(images);}
  }
});
  
var PhotobucketMediaPlugin = Class.create(GoogleMediaPlugin, {
  getName: function() {
    return 'photobucket';
  },
  setCustomRestrictions: function(gSearch) {
    gSearch.setSiteRestriction('photobucket.com');
  }
});

var ImageInfo = Class.create({
  initialize: function(title, url, thumbUrl, width, height) {
    this.title = title;
    this.url = url;
    this.thumbUrl = thumbUrl;
    this.width = width;
    this.height = height;
    this.type = 'image';
  },
  getElt: function() {
    //IE seems to distort images possibly with max-width/max-height css styling, so returning html instead
    return "<img src=" + this.thumbUrl + ' alt='+this.title + ' title='+this.title + ">";
    // img.alt = img.title = this.title;
    // img.onerror = this.imageLoadingError;
    // img.onload = this.imageLoadingCheck;
    return img;
  },
  shortDomain: function() {
    try {
      return this.creditsLink.match(/https{0,1}:\/\/(www\.){0,1}([^\/]*)\/*.*/i)[2];
    }
    catch(e) {
      var str = this.creditsLink.slice(0,20);
      if (str.length != this.creditsLink.length) {str +='...';}
      return str;
    }
  },
  fileInfo: function() {
    var info = '';
    if (this.width && this.height) {
      info += this.width + ' x ' + this.height;
    }
    if (this.fileSize) {
      info += ' - ' + Math.round(this.fileSize/1024) + 'k';
    }
    return info;
  },
  imageLoadingError: function() {
    this.src = "http://media.coolchaser.com/images/no_image.gif";
  },
  imageLoadingCheck: function() {
    if (this.width == 1 || this.height == 1) {
      this.src = "/images/no_image.gif";
    }
  },
  toGraphic: function() {
    return {title:this.title, asset_url:this.url, asset_type:this.type, source:this.engine, 
      credits_link:this.creditsLink, width:this.width, height:this.height//, size:this.fileSize
    };
  },
  toGraphicQueryStr: function(parent) {
    var graphic = this.toGraphic();
    return $H(graphic).collect(function(pair) {
      return encodeURIComponent(parent+'['+pair.key+']') + '=' + encodeURIComponent(pair.value);
    }).join('&');
  }
});

var VideoInfo = Class.create(ImageInfo, {
  initialize: function(title, url, query) {
    this.title = title;
    this.url = url;
    this.type = 'video';
  },
  getElt: function() {
    return "<object width=230 height=190><param name='move' value='" + this.url + "' />" + 
      "<embed src='" + this.url + "' type='application/x-shockwave-flash' width=230 heigh=190 /></object>";
    // IE doesn't seem to allow DOM level 2 objects, so using html text
    // var elt = new Element('object', {width:'230', height:'190'}).insert(
    //   new Element('param', {name:'move', value:this.url}));
    // elt.insert(new Element('embed', {src:this.url, type:'application/x-shockwave-flash', width:230, height:190}));
    // return elt;
  }
});

Element.showHide = function(elt, show) {
  if (show) {Element.show(elt);}
  else {Element.hide(elt);}
};
