var RichTextEditor = Class.create({
  initialize: function(){
    tinyMCE.init(this.editorOptions());
  },

  setEditorOption: function(option, value){
    options = this.editorOptions();
    options[option] = value;
  },
  
  appendToEditorOption: function(option, value){
    options = this.editorOptions();
    options[option] += value;    
  },
  
  editorOptions: function(){
    if(!this.editor_options){
      this.editor_options = {
        content_css: "/stylesheets/tinymce.css?" + new Date().getTime() + ",/stylesheets/sound_manager_player.css?" + new Date().getTime(),
        convert_urls : false,
        editor_selector: "richtexteditor",
        height: '200px',
        inline_styles: false,
        media_strict: false,
        mode: "specific_textareas", 
        plugins: "media,safari",
        relative_urls : false,
        setup: this.setupEditor.bind(this),
        theme: "advanced", 
        theme_advanced_buttons1: "bold,italic,underline,strikethrough,fontsizeselect,|,justifyleft,justifycenter,justifyright,blockquote,|,simplelink,simpleimage,youtube",
        theme_advanced_buttons2: "", 
        theme_advanced_buttons3: "",
        theme_advanced_toolbar_location: "top", 
        width: '100%'
      };
    }
    return this.editor_options;
  },
  
  customButtons: function(){
    return {
      youtube: RichTextEditor.CustomButtons.YouTubeButton,
      simplelink: RichTextEditor.CustomButtons.SimpleLinkButton,
      simpleimage: RichTextEditor.CustomButtons.SimpleImageButton
    };
  },

  displayMediaBrowser: function(editor){
    var win = Application.Window.makeModalFromRemote();
  },

  setupEditor: function(editor){
    $H(this.customButtons()).each(function(pair){
      editor.addButton(pair.key, pair.value(editor));
    })
  }
});

Object.extend(RichTextEditor, {
  addImage: function(editor, src){
    // Weird hack around TinyMCE's insertContent throwing an exception
    var imageElement = new Element('img', {src: src});
    var tempElement = (new Element('p')).update(imageElement);
    editor.execCommand('mceInsertContent', false, tempElement.innerHTML);
  },
  
  addLink: function(editor, link) {
    editor.execCommand('mceInsertLink', false, link);
  },
  
  addVideo: function(editor, videoEmbed) {
    editor.execCommand('mceInsertContent', false, videoEmbed);
  },
  
  addElement: function(editor, element){
    var tmp = new Element('p').update(element.cloneNode(true));
    editor.execCommand('mceInsertContent', false, tmp.innerHTML);
  },

  addImageFromUserInput: function(editor, event){
    var image = RichTextEditor.getText("Please enter an image URL.");
    if (image) {
      RichTextEditor.addImage(editor, image);
    } else {
      return true; // User just hit 'OK' or entered nothing. Maybe prompt again in future?      
    }
  },
  
  addLinkFromUserInput: function(editor, event){
    var link = RichTextEditor.getText("Please enter a link.");
    if(link) {
      RichTextEditor.addLink(editor, link);
    } else {
      return true; // User just hit 'OK' or entered nothing. Maybe prompt again in future?
    }
  },
  
  addVideoFromUserInput: function(editor, event){
    var videoEmbed = RichTextEditor.getText("Please paste the embed tags for the video you wish to insert.")
    if (videoEmbed) {
      RichTextEditor.addVideo(editor, videoEmbed);
    } else {
      return true; // User just hit 'OK' or entered nothing. Maybe prompt again in future?
    }
  },
  
  getText: function(prompt) {
    var text = window.prompt(prompt);
    if(text == null || text.blank()){
      return false;
    } else {
      return text;
    }
  }
});

RichTextEditor.CustomButtons = {
  YouTubeButton: function(editor){
    return { 
      title: 'Embed a Video from the Web', 
      image: '/images/icons/embed_movie.png',
      onclick: RichTextEditor.addVideoFromUserInput.curry(editor) };
  },
  
  SimpleLinkButton: function(editor){
    // Disable simplelink if no text is selected.
    editor.onNodeChange.add(function(editor, cm, n, co) {
      cm.setDisabled('simplelink', co && n.nodeName != 'A');
      cm.setActive('simplelink', n.nodeName == 'A' && !n.name);
    });

    return {
      title: 'Insert Link',
      image: '/images/icons/link.png',
      onclick: RichTextEditor.addLinkFromUserInput.curry(editor) };
  },
  
  SimpleImageButton: function(editor){
    return {
      title: 'Insert Image',
      image: '/images/icons/image.png',
      onclick: RichTextEditor.addImageFromUserInput.curry(editor) };
  },
  
  MediaBrowserButton: function(editor){
    var textarea = $(editor.editorId);
    var media_path = textarea.getAttribute("data-media-path");
    return {
      title: 'Embed your remix content',
      image: '/images/icons/media_browser.png',
      onclick: RichTextEditor.MediaBrowser.display.curry(editor, media_path) };
  }
};

var RichTextEditorWithMediaBrowser = Class.create(RichTextEditor, {
  initialize: function($super){
    var options = this.editorOptions();
    this.setEditorOption('editor_selector', 'richtextarea_with_mediabrowser');
    this.setEditorOption('init_instance_callback', 'RichTextEditorWithMediaBrowser.afterInitialized');
    this.appendToEditorOption('theme_advanced_buttons1', ',mediabrowser');
    $super();
  },
  
  customButtons: function($super) {
    return {
      youtube: RichTextEditor.CustomButtons.YouTubeButton,
      simplelink: RichTextEditor.CustomButtons.SimpleLinkButton,
      simpleimage: RichTextEditor.CustomButtons.SimpleImageButton,
      mediabrowser: RichTextEditor.CustomButtons.MediaBrowserButton };
  }
});

Object.extend(RichTextEditorWithMediaBrowser, {
  afterInitialized: function(){
    RichTextEditor.MediaBrowser.editorInitialized(tinyMCE.activeEditor);
  }
});

RichTextEditor.MediaBrowser = Class.create({
  initialize: function(editor, media_path){
    this.editor = editor;
    this.media_path = media_path;
  },
  
  display: function(){
    this.win = Application.Window.makeModalFromRemote(this.media_path, {
      onComplete: this.registerClickHandlers.bind(this)
    });
  },
  
  insertSelection: function(anchor){
    RichTextEditor.addElement(this.editor, anchor);
    this.win.close();
  },
  
  registerClickHandlers: function(win){
    win.content().down('#media_browser').select('.main .embedded').each(function(a){
      a.observeExclusively('click', this.insertSelection.bind(this, a));
    }.bind(this));
  }
});

RichTextEditor.MediaBrowser.editorInitialized = function(editor){
  /* Given an element and a desired class name this will return
     the first DOM element with that class or it will return
     nothing. This is here because the dynamically created
     iframe can't access Prototype's DOM traversal methods. */
  var findParentWithClass = function(node, className){
    var klass;
    while(true){
      if(!node.getAttribute || !node.parentNode){
        return;
      }
      klass = node.getAttribute("class");
      if(klass && klass.split(/\s+/).include(className)){
        return node;
      }
      node = node.parentNode;
    }
  };
  
  /* hasClassName is provided because the element
    being passed in comes from a dynamically generated iframe
    that does not have access to Prototype element methods. */
  var hasClassName = function(element, klass){
    element.className.split(/\s+/).each(function(n){
      if(n == klass) return true; 
    });
    return false;
  };
     
  /* addClassName is provided because the element
    being passed in comes from a dynamically generated iframe
    that does not have access to Prototype element methods. */
  var addClassName = function(element, klass){
    if(!hasClassName(element, klass)){
      element.className = element.className + " " + klass;
    }
  };
  
  /* removeClassName is provided because the element
    being passed in comes from a dynamically generated iframe
    that does not have access to Prototype element methods. */
  var removeClassName = function(element, klass){
    var current_klasses = element.className.split(/\s+/);
    var new_klasses = [];
    current_klasses.each(function(n){
      if(n != klass) new_klasses.push(n);
    });
    element.className = new_klasses.join(" ");
  };
  
  var last_selected;
  
  /* Returns true if the passed in element is the same 
    as the last selected remix element */
  var isElementSameAsLastSelected = function(element){
    return last_selected && element == last_selected;
  };
  
  /* Given the passed in element, attempts to find the
     first parent with the class "embedded". If one exists
     it will add the "selected" to it. */
  var selectEmbeddedRemixMedia = function(element){
    var embedded = findParentWithClass(element, "embedded")
    if(embedded){
      last_selected = embedded;
      addClassName(last_selected, "selected");
      editor.selection.select(last_selected);
    };
  };

  /* Deselects the passed in embedded remix media content */
  var deselectEmbeddedRemixMedia = function(element){
    removeClassName(element, "selected");
  };
  
  /* If the user selected a piece of embedded remix content
     then mark it as selected. If it's not then deselect it. */
  editor.onNodeChange.add(function(editor, _, element){
    if(isElementSameAsLastSelected(element)) return;
    if(last_selected) deselectEmbeddedRemixMedia(last_selected);
    selectEmbeddedRemixMedia(element);
  });

  /* Remove the "selected" class from embedded remix content
     before tinyMCE returns the content in the rich text editor */
  editor.onBeforeGetContent.add(function(editor, _){
    editor.dom.select(".embedded.selected").each(function(el){
      deselectEmbeddedRemixMedia(el);
    });

  });
};

RichTextEditor.MediaBrowser.display = function(editor, media_path){
  new RichTextEditor.MediaBrowser(editor, media_path).display();
};

// Only load this if tinyMCE has been previously loaded
if(typeof tinyMCE != "undefined"){
  new RichTextEditor();
  new RichTextEditorWithMediaBrowser();
}