function EpicEditor(options) {
    // Default settings will be overwritten/extended by options arg
    var self = this
      , opts = options || {}
      , _defaultFileSchema
      , _defaultFile
      , defaults = { container: 'epiceditor'
        , basePath: 'epiceditor'
        , textarea: undefined
        , clientSideStorage: true
        , localStorageName: 'epiceditor'
        , useNativeFullscreen: true
        , file: { name: null
        , defaultContent: ''
          , autoSave: 100 // Set to false for no auto saving
          }
        , theme: { base: '/themes/base/epiceditor.css'
          , preview: '/themes/preview/github.css'
          , editor: '/themes/editor/epic-dark.css'
          }
        , focusOnLoad: false
        , shortcut: { modifier: 18 // alt keycode
          , fullscreen: 70 // f keycode
          , preview: 80 // p keycode
          }
        , string: { togglePreview: 'Toggle Preview Mode'
          , toggleEdit: 'Toggle Edit Mode'
          , toggleFullscreen: 'Enter Fullscreen'
          }
        , parser: typeof marked == 'function' ? marked : null
        , autogrow: false
        , button: { fullscreen: true
          , preview: true
          , bar: "auto"
          }
        }
      , defaultStorage
      , autogrowDefaults = { minHeight: 80
        , maxHeight: false
        , scroll: true
        };

    self.settings = _mergeObjs(true, defaults, opts);
    
    var buttons = self.settings.button;
    self._fullscreenEnabled = typeof(buttons) === 'object' ? typeof buttons.fullscreen === 'undefined' || buttons.fullscreen : buttons === true;
    self._editEnabled = typeof(buttons) === 'object' ? typeof buttons.edit === 'undefined' || buttons.edit : buttons === true;
    self._previewEnabled = typeof(buttons) === 'object' ? typeof buttons.preview === 'undefined' || buttons.preview : buttons === true;

    if (!(typeof self.settings.parser == 'function' && typeof self.settings.parser('TEST') == 'string')) {
      self.settings.parser = function (str) {
        return str;
      }
    }

    if (self.settings.autogrow) {
      if (self.settings.autogrow === true) {
        self.settings.autogrow = autogrowDefaults;
      }
      else {
        self.settings.autogrow = _mergeObjs(true, autogrowDefaults, self.settings.autogrow);
      }
      self._oldHeight = -1;
    }

    // If you put an absolute link as the path of any of the themes ignore the basePath
    // preview theme
    if (!self.settings.theme.preview.match(/^https?:\/\//)) {
      self.settings.theme.preview = self.settings.basePath + self.settings.theme.preview;
    }
    // editor theme
    if (!self.settings.theme.editor.match(/^https?:\/\//)) {
      self.settings.theme.editor = self.settings.basePath + self.settings.theme.editor;
    }
    // base theme
    if (!self.settings.theme.base.match(/^https?:\/\//)) {
      self.settings.theme.base = self.settings.basePath + self.settings.theme.base;
    }

    // Grab the container element and save it to self.element
    // if it's a string assume it's an ID and if it's an object
    // assume it's a DOM element
    if (typeof self.settings.container == 'string') {
      self.element = document.getElementById(self.settings.container);
    }
    else if (typeof self.settings.container == 'object') {
      self.element = self.settings.container;
    }

    if (typeof self.settings.textarea == 'undefined' && typeof self.element != 'undefined') {
      var textareas = self.element.getElementsByTagName('textarea');
      if (textareas.length > 0) {
        self.settings.textarea = textareas[0];
        _applyStyles(self.settings.textarea, {
          display: 'none'
        });
      }
    }
    
    // Figure out the file name. If no file name is given we'll use the ID.
    // If there's no ID either we'll use a namespaced file name that's incremented
    // based on the calling order. As long as it doesn't change, drafts will be saved.
    if (!self.settings.file.name) {
      if (typeof self.settings.container == 'string') {
        self.settings.file.name = self.settings.container;
      }
      else if (typeof self.settings.container == 'object') {
        if (self.element.id) {
          self.settings.file.name = self.element.id;
        }
        else {
          if (!EpicEditor._data.unnamedEditors) {
            EpicEditor._data.unnamedEditors = [];
          }
          EpicEditor._data.unnamedEditors.push(self);
          self.settings.file.name = '__epiceditor-untitled-' + EpicEditor._data.unnamedEditors.length;
        }
      }
    }

    if (self.settings.button.bar === "show") {
      self.settings.button.bar = true;
    }

    if (self.settings.button.bar === "hide") {
      self.settings.button.bar = false;
    }

    // Protect the id and overwrite if passed in as an option
    // TODO: Put underscrore to denote that this is private
    self._instanceId = 'epiceditor-' + Math.round(Math.random() * 100000);
    self._storage = {};
    self._canSave = true;

    // Setup local storage of files
    self._defaultFileSchema = function () {
      return {
        content: self.settings.file.defaultContent
      , created: new Date()
      , modified: new Date()
      }
    }

    if (localStorage && self.settings.clientSideStorage) {
      this._storage = localStorage;
      if (this._storage[self.settings.localStorageName] && self.getFiles(self.settings.file.name) === undefined) {
        _defaultFile = self._defaultFileSchema();
        _defaultFile.content = self.settings.file.defaultContent;
      }
    }

    if (!this._storage[self.settings.localStorageName]) {
      defaultStorage = {};
      defaultStorage[self.settings.file.name] = self._defaultFileSchema();
      defaultStorage = JSON.stringify(defaultStorage);
      this._storage[self.settings.localStorageName] = defaultStorage;
    }

    // A string to prepend files with to save draft versions of files
    // and reset all preview drafts on each load!
    self._previewDraftLocation = '__draft-';
    self._storage[self._previewDraftLocation + self.settings.localStorageName] = self._storage[self.settings.localStorageName];

    // This needs to replace the use of classes to check the state of EE
    self._eeState = {
      fullscreen: false
    , preview: false
    , edit: false
    , loaded: false
    , unloaded: false
    }

    // Now that it exists, allow binding of events if it doesn't exist yet
    if (!self.events) {
      self.events = {};
    }

    return this;
  }
Initiates the EpicEditor object and sets up offline storage as well
@class Represents an EpicEditor instance
@param {object} options An optional customization object
@returns {object} EpicEditor will be returned