(function($) {
  /**
  *
  *	simpleTooltip jQuery plugin, by Marius ILIE
  *	visit http://dev.mariusilie.net for details
  *
  **/
  $.fn.simpletooltip = function(opts){
    var fn = $.fn.simpletooltip;
  	return this.each(function() {
  		var text = opts || $(this).attr("title");
  		$(this).removeAttr("title");
  		$(this).data('text', text);
  		if(text && text.length) {
  			$(this).hover(fn.over, fn.out);
  			$(this).mousemove(fn.move);
  		} else {
  		  $(this).unbind('mouseenter', $.fn.simpletooltip.over);
  		  $(this).unbind('mouseleave', $.fn.simpletooltip.out);
  		  $(this).unbind('mousemove', $.fn.simpletooltip.move);
  		}
  	});
  };
  
  $.fn.simpletooltip.over = function(e) {
    var $this = $(this);
    if ($this.is(':hidden') || !$this.data('text')) return;
		var tipX = e.pageX + 12;
		var tipY = e.pageY + 12;
		$this.attr("title", ""); 
		$("body").append($("<div id='simpleTooltip' style='position: absolute; z-index: 3000; display: none;' />").text($this.data('text')));
		var tipWidth = $.browser.msie?$("#simpleTooltip").outerWidth(true):$("#simpleTooltip").width();
		$("#simpleTooltip").width(tipWidth);
		$("#simpleTooltip").css("left", tipX).css("top", tipY).fadeIn("medium");
  };
  
  $.fn.simpletooltip.out = function(e) {
		$("#simpleTooltip").remove();
  };
  
  $.fn.simpletooltip.move = function(e){
    var $this = $(this);
    if ($this.is(':hidden') || !$this.data('text')) return;
		var tipX = e.pageX + 12;
		var tipY = e.pageY + 12;
		var tipWidth = $("#simpleTooltip").outerWidth(true);
		var tipHeight = $("#simpleTooltip").outerHeight(true);
		if(tipX + tipWidth > $(window).scrollLeft() + $(window).width()) tipX = e.pageX - tipWidth;
		if($(window).height()+$(window).scrollTop() < tipY + tipHeight) tipY = e.pageY - tipHeight;
		$("#simpleTooltip").css("left", tipX).css("top", tipY).fadeIn("medium");
	};
  
  // Scope EA for us.
  var EA = $.EA = $.EA || {};
  
  // Scope Replay
  var plan = $.EA.plan = {
    prefix: 'epicplan_'
  };
  
  // plan Icon Stuff closure
  (function() { // is called immedately
    // private vars for IconDb
    var db = {},
      defaults = {  
        src: 'http://s3.epicplan.com/icons/inv_misc_questionmark.png',
        width: 32,
        height: 32
      };
    
    plan.IconDb = {
      loadIconInfo: function(opts) {
        if(opts.constructor == Array) {
          $.each(opts, function(i,v) { plan.IconDb.loadIconInfo(v); });
          return;
        }
        // extend empty object with defaults and options
        var info = $.extend({}, defaults, opts); 
        if (!info.name) {
          throw "No Name Passed to loadIconInfo";
        }
        if (db.hasOwnProperty(info.name)) {
          return; // already have this icon
        }
        db[info.name] = info;
      },
      getIconInfo: function(name){
        if (arguments.length == 0) return db;
        if (name && db.hasOwnProperty(name)) {
          return db[name];
        }
        return $.extend({},defaults); // clone defaults
      }
    };
    
    plan.IconFactory = function(name, callback) {
      if (!callback || typeof callback != "function") callback = function() {};
      var info = plan.IconDb.getIconInfo(name);
      var dom = $("<img>").bind("load", callback).attr({width: info.width, height: info.height, src: info.src}).addClass(plan.prefix+'icon');
      return new plan.Icon(info,dom);
    };
  
    plan.Icon = function(info, dom) {
      this.$ = dom;
      this.info = info;
      this.scale = 1.0;
    };
  
    plan.Icon.prototype.setScale = function(scale, overms, callback) {
      if (!scale) scale = 1;
      scale = parseFloat(scale);
      this.scale = scale;
      this.width = this.info.width * scale;
      this.height = this.info.height * scale;
      this.$.stop(true,true).animate({width: this.width, height: this.height}, overms, callback);
      
      return this;
    };
  })(); // plan icon closure

  // plan Map Stuff closure
  (function() { // is called immedately
    // private vars for MapDb
    var db = {},
      defaults = {  
        src: '/images/design/maps/grid.gif',
        width: 1000,
        height: 1000,
        scaleFactor: 1.0,
        focus: {x:0,y:0}
      };
    
    plan.MapDb = {
      loadMapInfo: function(opts) {
        if(opts.constructor == Array) {
          $.each(opts, function(i,v) { plan.MapDb.loadMapInfo(v); });
          return;
        }
        // extend empty object with defaults and options
        var info = $.extend({}, defaults, opts); 
        if (!info.name) {
          return;
        }
        // if (db.hasOwnProperty(info.name)) {
        //   return; // already have this map
        //   throw "Attempt to overwrite an existing map";          
        // }
        db[info.name] = info;
      },
      getMapInfo: function(name){
        if (arguments.length == 0) return db;
        if (name && db.hasOwnProperty(name)) {
          return db[name];
        }
        return $.extend({},defaults); // clone defaults
      }
    };
    
    plan.MapFactory = function(name, callback) {
      if (!callback || typeof callback != "function") callback = function() {};
      var info = plan.MapDb.getMapInfo(name);
      var dom = $("<img>").bind("load", callback).attr({width: info.width, height: info.height, src: info.src}).addClass(plan.prefix+'map');
      return new plan.Map(info,dom);
    };
  
    plan.Map = function(info, dom) {
      this.$ = dom;
      this.info = info;
      this.scale = info.scaleFactor;
      this.x = info.focus.x;
      this.y = info.focus.y;
    };
    
    plan.Map.prototype.updateStyle = function(overms, callback) {
      this.$.stop(true,true).animate({
        width: this.info.width * this.scale,
        height: this.info.height * this.scale,
        left: "-"+(this.x)+"px",
        top: "-"+(this.y)+"px"
      }, overms, callback);
      return this;
    };
  
    plan.Map.prototype.setScale = function(scale, overms, callback) {
      if (!scale) scale = 1;
      scale = parseFloat(scale);
      this.scale = scale;
      this.updateStyle(overms,callback);
      return this;
    };
    
    plan.Map.prototype.setInfo = function(info, overms, callback) {
      this.info = info;
      this.scale = info.scaleFactor;
      this.x = info.focus.x;
      this.y = info.focus.y;
      this.updateStyle(overms, callback);
    };
  })(); // plan icon closure

  
  // Unit Class Closure
  (function() {
    plan.Unit = function(opts) {
      this.$ = $("<li>").addClass(plan.prefix+'unit');
      this.set(opts, 0);
    };
    
    plan.Unit.prototype = {
      set: function(opts, overms, callback){
        opts = $.extend({},opts); // opts gets destroied otherwise
        if (opts.hasOwnProperty('hidden')) {
          this.setHidden(opts.hidden);
          delete opts.hidden;
        }
        
        // set options
        if (opts.icon) {
          this.setIcon(opts.icon);
          delete opts.icon;
        }
        if (opts.position) {
          this.setPosition(opts.position, overms);
          delete opts.position;
        }
        if (opts.id) {
          this.setId(opts.id, overms);
          delete opts.id;
        }        
        if (opts.scale) {
          this.setScale(opts.scale, overms);
          delete opts.scale;
        }
        if (opts.title) {
          this.setTitle(opts.title);
          delete opts.title;
        }
        // everything else is a option to just push into the meta
        $.extend(this, opts);
        this.updateStyle(overms, callback);
        return this; 
      },
      setHidden: function(hidden) {
        if (hidden) {
          this.hidden = true;
        } else {
          this.hidden = false;
        }
        return this;
      },
      setTitle: function(title) {
        this.title = title;
        this.$.simpletooltip(title);
        return this;
      },
      setId: function(id) {
        this.id = id;
        this.$.attr('id', id);
        return this;
      },
      _opacity: function() {
        if (this.hidden) return 0;
        return 1;
      },
      updateStyle: function(overms, callback) {
        if (this.hidden)
        {
          overms = 0;
        } else {
        }
        var upd = {
          left: this.x,
          top: this.y,
          width: this._icon ? this._icon.width || this._icon.info.width : 'auto',
          height: this._icon ? this._icon.height || this._icon.info.height : 'auto',
          opacity: this._opacity()
        };
        this.$.stop(true,true).animate(upd, overms, callback).css({'position':'absolute'});        
      },
      setPosition: function(position, overms, callback) {
        this.x = position.x;
        this.y = position.y;
      },
      setScale: function(scale, overms, callback) {
        if (this._icon) {
          this._icon.setScale(scale, overms);
        }
        return this;
      },
      setIcon: function(icon) {
        if (typeof icon == 'string') {
          if (this.icon == icon) return;
          this.icon = icon;
          icon = plan.IconFactory(icon);
        } else {
          this.icon = null;
        }
        if (icon.constructor !== plan.Icon)
        {
          throw "Not an Icon";
        }
        if (this._icon) {
          this._icon.$.remove();
        }
        this._icon = icon;
        if (icon) this.$.append(icon.$);
        return this;
      }
    };
    
    // UnitList class
    plan.UnitList = function(units) {
      var db = {}, ul = this;
      this.$ = $("<ul/>").addClass(plan.prefix+'unitlist');
      this.getUnit = function(id) {
        if (db.hasOwnProperty(id)) return db[id];
        throw "Unknown Unit "+id;
      };
      this.addUnit = function(id, unit) {
        if (db.hasOwnProperty(id)) throw "Already have a unit named that";
        if (unit.constructor !== plan.Unit) unit = new plan.Unit(unit);
        db[id] = unit;
        db[id].setId(id);
        if (unit.list) {
          if (unit.list === this) return this;
          throw "Unit can't be in two lists";
        }
        unit.set({list: this});
        this.$.append(unit.$);
        return this;
      };
      this.addUnits = function(units) {
        $.each(units, function(id, unit) {
          ul.addUnit(id,unit);
        });        
      };
      this.removeUnit = function(id) {
        if (db.hasOwnProperty(id))
        {
          db[id].set({list: null});
          db[id].$.remove();
          delete db[id];
        }
        return this;
      };
      this.updateUnits = function(data, overms, callback) {
        $.each(data,function(unit, opts) {
          ul.getUnit(unit).set(opts, overms);
        });
        if (typeof callback == 'function') {
          return setTimeout(callback, overms);
        }
      };
      this.getUnits = function() {
        return db;
      };
      
      if (units) {
        this.addUnits(units);
      }
      
    };
  })();
  
  plan.TitleControl = function(viewport) {
    this.viewport = viewport;
    this.buildControls();
    this.attachEvents();
  };
  plan.TitleControl.prototype = {
    buildControls: function() {
      var control = this, vp = this.viewport;
      var controls = control.controls = {
        $container: $('<div />').addClass(plan.prefix+'title'),
        $back: $("<a />").addClass(plan.prefix+'button').addClass('back'),
        $next: $("<a />").addClass(plan.prefix+'button').addClass('next'),
        $text: $("<div />")
      };
      
      this.$ = controls.$container.append(
        controls.$back.css({'float': 'left'}),
        controls.$next.css({'float': 'right'}),
        controls.$text
      );
      
    },
    setTitle: function(title) {
      var control = this, vp = this.viewport, controls = this.controls;
      this.title = title;
      controls.$text.text(title);
    },
    attachEvents: function() {
      var control = this, vp = this.viewport, controls = this.controls;
      controls.$back.click(function(e) {
        vp.timeline.loopPrevTitle();
        e.stopPropagation();
        e.preventDefault();
        return false;
      });
      controls.$next.click(function(e) {
        vp.timeline.loopNextTitle();
        e.stopPropagation();
        e.preventDefault();
        return false;
      });
      controls.$container.hover(function() {
        controls.$container.stop(true).animate({opacity: 0.9}, 150);
      },function() {
        controls.$container.stop(true).animate({opacity: 0.5}, 500);
      });
    }
  };
  
  // Viewport Closure
  (function() {
    plan.Viewport = function(opts) {
      if (!opts) opts = {};
      this.$ = $("<div />").addClass(plan.prefix+'viewport');
      this.set(opts);
    };
    
    
    plan.Viewport.prototype = {
      set: function(opts) {
        if (opts.map) {
          this.setMap(opts.map);
          delete opts.map;
        }
        if (opts.title) {
          this.setTitle(opts.title);
          delete opts.title;
        }
        if (opts.unitList) {
          this.setUnitList(opts.unitList);
          delete opts.unitList;
        }
        if (opts.timeline) {
          this.setTimeLine(opts.timeline);
          delete opts.timeline;
        }
        $.extend(this, opts);
      },
      setTitle: function(title) {
        if (!this.title) {
          this.title = new plan.TitleControl(this);
          this.$.append(this.title.$);
        }
        this.title.setTitle(title);
      },
      setMap: function(map, overms, callback) {
        var vp = this;
        if (arguments.length == 0) return;
        if (arguments.length < 2) {
          overms = 1000;
          callback = function() {};
        }
        if (arguments.length < 3) {
          if (typeof overms == 'function') {
            callback = overms;
            overms = 1000;
          } else {
            callback = function() {};
          }
        }
        var oldmap = this.map;
        if (oldmap && (oldmap.info.name == map)) {
          // oldmap.updateStyle(overms);
          return callback();
        }
        var info = plan.MapDb.getMapInfo(map);
        if (oldmap && (oldmap.info.src == info.src))
        {
          oldmap.setInfo(info,overms,callback);
          return;
        }
        map = this.map = plan.MapFactory(map, function() {
          if (oldmap) oldmap.$.fadeOut(overms, function() { $(this).remove(); });
          vp.$.prepend(map.$);
          map.updateStyle(overms, callback);

        });
      },
      setTimeline: function(timeline) {
        if (this.timeline) {
          this.timeline.$.remove();
          this.timeline.viewport = null;
        }
        this.timeline = timeline;
        this.$.append(this.timeline.$);
        this.timeline.viewport = this;
        this.timeline.attachEvents();
        this.timeline.playFrame(0,0);
      },
      setUnitList: function(ul) {
        if (this.ul) {
          this.ul.$.remove();
        }
        if (ul.constructor !== plan.UnitList) {
          ul = new plan.UnitList(ul);
        }
        this.ul = ul;
        this.$.append(this.ul.$); // unitlist on top.
      },
      setPlan: function(aplan) {
        this.setUnitList(aplan.unitList);
        this.setTimeline(aplan.timeline);
      },
      getUnitList: function() {
        if (!this.ul) this.setUnitList(new plan.UnitList());
        return this.ul;
      }
    };

  })();

  // KeyFrame / TimeLine Class
  (function() {
    plan.Keyframe = function(opts) {
      this.set($.extend({}, plan.Keyframe.defaults, opts));
      plan.Keyframe.defaults.unitUpdates = {};  // make a new empty unitUpdate object for the next default
    };
    
    plan.Keyframe.defaults = {
      playTime: 1000,
      delay: 2500,
      map: null,
      unitUpdates: {},
      title: null,
      description: ''
    };
    
    plan.Keyframe.prototype = {
      set: function(opts){
        if (arguments.length == 1)
        {          
          // Copy the object, and delete the "expando"
          var copy = $.extend({}, opts);
          var temp = {};
          $.data(temp, 'test', 'test');
          for (var k in temp) delete copy[k];
          
          $.extend(this, copy);          
        }
        if (arguments.length == 2)
        {
          var data = {};
          data[arguments[0]]=arguments[1];
          this.set(data); 
        }
      },
      hasSet: function(property) {
        return this[property] !== null;
      },
      before: function(after) {
        // creates a copy of this keyframe using "after" as a base
        var propterty, clone = new plan.Keyframe(after);
        clone.unitUpdates = $.extend({}, this.unitUpdates);
        if (!after) return clone;
        $.each(after.unitUpdates, function(unit, update) {
          clone.unitUpdates[unit] = $.extend({}, clone.unitUpdates[unit], update);
        });
        if (this.title && !clone.title) clone.title = this.title;
        if (this.map && !clone.map) clone.map = this.map;
        return clone;
      },
      after: function(before) {
        return before.before(new plan.Keyframe(this));
      }
    };
    
    plan.Timeline = function(frames) {
      var db = [], tl = this;
      var _bfCache = [];
      this.paused = true;
      this.frame = 0;
      this.numFrames = function() {
        return db.length;
      };
      this.addFrame = function(frame, position) {
        _bfCache.splice(position,_bfCache.length);
        if (arguments.length < 2) position = db.length;
        if (frame.constructor != plan.Keyframe) {
          frame = new plan.Keyframe(frame);
        }
        db.splice(position, 0, frame);
      };
      this.removeFrame = function(frameno) {
        if (frameno == 0) {
          if (db.length <= 1) return false;
          db[1] = this.buildFrame(1);
        }
        _bfCache.splice(frameno,_bfCache.length);
        // method for deleting frame:
        db.splice(frameno, 1);
      };
      this.addFrames = function(frames) {
        $.each(frames,function(idx, frame) { tl.addFrame(frame); });
      };
      this.getFrame = function(frameno) {
        return db[frameno];
      };
      this.getFrames = function() {
        return db;
      };
      this.buildFrame = function(frameno, usecache) {
        if (usecache && _bfCache[frameno]) { return _bfCache[frameno]; }
        // recursion function
        var newFrame = this.getFrame(frameno);
        if (!newFrame) return newFrame;
        _bfCache.splice(frameno, _bfCache.length);
        if (frameno == 0) return _bfCache[0] = new plan.Keyframe(newFrame);
        var lastFrame = this.buildFrame(frameno-1,usecache);
        return _bfCache[frameno] = lastFrame.before(newFrame);
      };
      this.addFrames(frames);
      this.buildControls();
    };
    
    plan.Timeline.prototype = {
      updateViewport: function(frame, overms, callback) {
        if (!this.viewport) {
          throw "Can't play frame without a viewport";
        }
        if (frame.title !== null) {
          this.viewport.setTitle(frame.title);
        }
        if (frame.map !== null) {
          this.viewport.setMap(frame.map, overms);
        }
        if (frame.unitUpdates) {
          return this.viewport.getUnitList().updateUnits(frame.unitUpdates, overms, callback);
        }
        if (callback) return setTimeout(callback, overms);
      },
      
      // TODO: Fix this broken ass logic with pausing and nextframe
      playFrame: function(frameno, overms) {
        var frame = this.buildFrame(frameno, true);
        if (!frame) return;
        if (arguments.length<2) overms = frame.playTime;
        var tl = this;
        if (tl.nfTimeout) clearTimeout(tl.nfTimeout);
        if (tl.efCallback) clearTimeout(tl.efCallback);
        this.playing=true;
        var callback = function() {
          if (!tl.paused) tl.nfTimeout = setTimeout(function() {
            delete tl.nfTimeout; 
            if (tl.paused) return;
            if (tl.titleLoop && (tl.frame+1 == tl.numFrames() || tl.getFrame(tl.frame + 1).title))
            {
              tl.efCallback = setTimeout(function() {
                delete tl.efCallback;
                if (tl.titleLoop) {
                  tl.playFrame(tl.titleLoop,0);
                }
              }, 5000);
            } else {
              if (tl.frame < tl.numFrames())
              {
                tl.playFrame(tl.frame + 1);
              }              
            }
          }, frame.delay);
          tl.playing=false;
          if (tl.stopping) tl.stopping();
        };
        this.frame = frameno;

        tl.efCallback = this.updateViewport(frame, overms, function() {
          delete tl.efCallback;
          callback();
        });
        this.updateFrame();
      },
      loopNextTitle: function() {
        var curframe = this.frame;
        var nextTitle = curframe+1;
        while ((nextTitle < this.numFrames()) && !this.getFrame(nextTitle).title) nextTitle++;
        if (nextTitle >= this.numFrames()) {
          return;
        } else {
          this.titleLoop = nextTitle;
          this.paused = false;
          this.playFrame(nextTitle);
        }
      },
      loopPrevTitle: function() {
        var curframe = this.frame;
        var prevTitle = curframe;
        while ((prevTitle > 0) && !this.getFrame(prevTitle).title) prevTitle--; // found this one
        prevTitle--;
        while ((prevTitle > 0) && !this.getFrame(prevTitle).title) prevTitle--; // found the previous one
        if (prevTitle < 0) {
          return;
        } else {
          this.titleLoop = prevTitle;
          this.paused = false;
          this.playFrame(prevTitle);
        }
      },
      getFrame: function() {
        return this.frame;
      },
      nextFrame: function() {
        if ((this.frame < this.numFrames()) && !this.paused)
        {
          this.playFrame(++this.frame);
        }
      },
      gotoFrame: function(frameno, overms, callback) {
        var frame = this.buildFrame(frameno, true);
        if (!frame) return false;
        if (arguments.length < 2) overms = frame.playTime;
        this.frame = frameno;
        this.updateViewport(frame, overms, callback);
        this.updateFrame();
      },
      buildControls: function() {
        var tl=this;
        var $timeline = this.$ = $("<div/>").addClass(plan.prefix+'timeline');
        var $replay = $("<a>").addClass(plan.prefix+'button').addClass('wayback');
        var $playpause = $("<a>").addClass(plan.prefix+'button').addClass('play');
        var $next = $("<a>").addClass(plan.prefix+'button').addClass('next');
        var $back = $("<a>").addClass(plan.prefix+'button').addClass('back');
        var waspaused = true;
        var $frame = $("<div/>").addClass(plan.prefix+'frameno').slider({min:0, max:tl.numFrames()-1, 
          start: function(event,ui) {
            waspaused = tl.paused;
            tl.pause();
          },
          stop: function(event,ui) {
            if (!waspaused) tl.play();
          },
          slide: function(event,ui) {
            if (tl.frame != ui.value) tl.gotoFrame(ui.value);
        }});
        $timeline.append($replay, $back);
        $timeline.append($playpause, $next);
        $timeline.append($frame);
        $playpause.update = function(paused) {
          $playpause.removeClass("play").removeClass("pause");
          $playpause.addClass(paused?"play":"pause");
        };
        tl.updateFrame = function() {
          $playpause.update(tl.paused);
          $frame.slider('value',tl.frame);
          if (tl.frame >= tl.numFrames()-1)
          {
            $playpause.update(true);
          }
          $frame.slider('option', 'max', tl.numFrames()-1);
        };
        tl.play = function(frame) {
          $playpause.update(false);
          tl.paused = false;
          if (arguments.length < 1)
            tl.nextFrame();
          else 
            tl.playFrame(frame, 0);
        };
        tl.pause = function() {
          $playpause.update(true);
          if (tl.efCallback) clearTimeout(tl.efCallback);          
          if (tl.nfTimeout) clearTimeout(tl.nfTimeout);
          tl.playing = false;
          tl.paused = true; 
          tl.titleLoop = false;
        };
        tl.restart = function() {
          tl.pause();
          tl.stopping = function() {
            tl.play(0);
            delete tl.stopping;
          };
          if (!tl.playing) tl.stopping();
        };
        this.attachEvents = function() {
          var ffTimers = {
            clear: function() {
              if (this.timeout) {
                clearTimeout(this.timeout);
                delete this.timeout;
              }
              if (this.interval) {
                clearInterval(this.interval);
                delete this.interval;
              }
            }
          };
          $next.click(function(e) {
          }).bind('mousedown', function(e) {
            ffTimers.clear();
            ffTimers.timeout = setTimeout(function() {
              tl.pause();
              var ff= function() {
                delete ffTimers.timeout;
                tl.gotoFrame(tl.frame +1, 150);
              };
              ffTimers.interval = setInterval(ff, 200);
            }, 300);
          }).bind('mouseup', function(e) {
            if (ffTimers.timeout) tl.gotoFrame(tl.frame + 1);
            ffTimers.clear();
          });
          $back.click(function(e) {
          }).bind('mousedown', function(e) {
              ffTimers.clear();
              ffTimers.timeout = setTimeout(function() {
                tl.pause();
                var ff= function() {
                  delete ffTimers.timeout;
                  tl.gotoFrame(tl.frame - 1, 150);
                };
                ffTimers.interval = setInterval(ff, 200);
              }, 300);
            }).bind('mouseup', function(e) {
              if (ffTimers.timeout) tl.gotoFrame(tl.frame - 1, 250);
              ffTimers.clear();
          });;
          $replay.click(function(e) {
            tl.restart();
            e.preventDefault();
            e.stopPropagation();
          });
          $playpause.click(function(e) {
            if (tl.frame>=tl.numFrames()-1)
            {
              tl.play(0);
            } else if (tl.paused) {
              tl.play();
            } else {
              tl.pause();
            }
            e.preventDefault();
            e.stopPropagation();
          });
        };
      }
    };
  })();
  
  (function() {
    plan.Plan = function(data) {
      $.extend(this, {
        timeline: null,
        mapInfo: null,
        iconInfo: null
      });
      this.set(data);
    };
    
    plan.Plan.prototype = {
      set: function(data){
        data = $.extend({}, data);
        if (data.iconInfo) {
          plan.IconDb.loadIconInfo(data.iconInfo);
        }
        if (data.mapInfo) {
          plan.MapDb.loadMapInfo(data.mapInfo);
        }
        if (data.timeline) {
          if (data.timeline.constructor === plan.Timeline)
          {
            this.timeline = data.timeline;
          } else {
            this.timeline = new plan.Timeline(data.timeline);
          }
          delete data.timeline;
        }
        if (data.unitList) {
          if (data.unitList.constructor === plan.UnitList)
          {
            this.unitList = data.unitList;
          } else {
            this.unitList = new plan.UnitList(data.unitList);
          }
          delete data.unitList;
        } else {
          this.unitList = this.timeline.getFrame(0).unitUpdates;
        }
        $.extend(this, data); 
      }      
    };
  })();
  
  if (typeof $.fn.slider != 'function')
  {
    $.fn.slider = function() {return this;}; // if you aren't using slider, dont use the slider?
  }
})(jQuery);
