var Comments = {};

Comments.Previewer = Class.create({
  initialize: function(element, form) {
    
    this.element = $(element);
    this.form    = $(form);
    
    this.getFields();
    this.getSlots();
        
    this.addObservers();
    
    // Initialize the Markdown converter.
    this.converter = new Showdown.converter();
    
    this.updatePreview();
  },
  
  addObservers: function() {
    this.formObserver = new Form.Observer(this.form, 0.5, this.updatePreview.bind(this));
  },
  
  updatePreview: function() {
    var values = this.getValues(), s = this.slots;

    s.author.update(values.author.blank() ?
     "<span class='placeholder'>[your name here]</span>" : values.author);
    s.comment.update(values.comment.blank() ?
     "<span class='placeholder'>[your comment here]</span>" :
      this.converter.makeHtml(values.comment));
      
    this.element.fire("preview:updated");
  },
  
  getFields: function() {
    var fields = {
      author:  $('author') || this.form.down('.post-comment-logged-in a'),
      url:     $('url'),
      comment: this.form.down('textarea')
    };
    
    this.fields = fields;
  },
  
  getSlots: function() {
    var slots = {
      author:  this.element.down('.comment-author'),
      comment: this.element.down('.comment-body')
    };
    
    this.slots = slots;
  },
  
  getValues: function() {
    if (!this.fields) {
      throw "Fields not initialized!";
    }
    
    var f = this.fields, values = {};
    
    if (f.author) {
      values.author = (f.author.nodeName.toUpperCase() === "INPUT") ?
        f.author.getValue() : f.author.innerHTML;
        
      if (!values.author) {
        values.author = $('openid').getValue();
      }
        
    }
    
    
    if (f.url) {
      values.url = f.url.getValue();
    }
    
    if (f.comment) {
      values.comment = f.comment.getValue();
    }
    
    return values;    
  }
});

Object.extend(Comments, {
  quote: function(event) {
    function getURL() {
      var url = window.location.toString();
      return url.split('#')[0];
    }
    
    var anchor      = event.element();
    var comment     = anchor.up('li.comment-item');    
    var commentText = comment.down('div.comment-body').innerHTML;    
    var cite        = getURL() + "#" + comment.readAttribute('id');
    
    var textarea = $('comment');
    
    textarea.value += this.toBlockQuote(commentText, cite);
    textarea.scrollTop = textarea.scrollHeight;
    
    function scrollIntoView() {
      $('comment').scrollTo().focus();
      document.stopObserving("preview:updated", scrollIntoView);
    }
    
    document.observe("preview:updated", scrollIntoView);
  },
  
  toBlockQuote: function(string, cite) {
    var citeAttr = cite ? ' cite="' + cite + '"' : '';    
    return "<blockquote#{0}>#{1}</blockquote>".interpolate([citeAttr, string]);
  },
  
  attributeBlockQuotes: function(element) {
    if (element === document) element = $(document.body);
    
    element.select('blockquote[cite]').each( function(bq) {
      if (bq._attributed) return;
      
      bq.insert({ 
        bottom: "<small class='citation'>(<a href='#{0}'>Source</a>)</small>".interpolate(
          [bq.readAttribute('cite')])
      });
      
      bq._attributed = true;
    });
  },
  
  
  convertSelectionToCode: function(event) {
    event.stop();
    var comment = $('comment'), selection;

    if (comment.setSelectionRange) {
      var val = $F(comment);
      selection = val.substring(comment.selectionStart, comment.selectionEnd);
      if (selection.length <= 0) { return false; }

      var pre  = val.substring(0, comment.selectionStart), 
          post = val.substring(comment.selectionEnd, comment.value.length);

      comment.value = pre + this.toCodeBlock(selection) + post;
      return true;
    } else {
      selection = document.selection.createRange().text;
      if (selection.length <= 0) { return false; }

      document.selection.createRange().text = this.toCodeBlock(selection);
    }
  },
  
  toCodeBlock: function(text) {
    return "<pre><code>" + text.escapeHTML() + "</code></pre>";;
  }     
});

Form.GhostedField = Class.create({
  initialize: function(element, title, options) {
    this.element = $(element);
    this.title = title;
    
    this.isGhosted = true;
    
    if (options.cloak) {
      // Wrap the native getValue function so that it never returns the
      // ghosted value. This is optional because it presumes the ghosted
      // value isn't valid input for the field.
      this.element.getValue = this.element.getValue.wrap(this.wrappedGetValue.bind(this));      
    }    
    
    this.addObservers();
    this.onBlur();
  },
  
  wrappedGetValue: function($proceed) {
    var value = $proceed();
    return value === this.title ? "" : value;
  },
  
  addObservers: function() {
    this.element.observe('focus', this.onFocus.bind(this));
    this.element.observe('blur',  this.onBlur.bind(this));
    
    var form = this.element.up('form');
    if (form) {
      form.observe('submit', this.onSubmit.bind(this));
    }
    
    // Firefox's bfcache means that form fields need to be re-initialized
    // when you hit the "back" button to return to the page.
    if (Prototype.Browser.Gecko) {
      window.addEventListener('pageshow', this.onBlur.bind(this), false);
    }
  },
  
  onFocus: function() {
    if (this.isGhosted) {
      this.element.setValue('');
      this.setGhosted(false);
    }
  },
  
  onBlur: function() {
    var value = this.element.getValue();
    if (value.blank() || value == this.title) {
      this.setGhosted(true);
    } else {
      this.setGhosted(false);
    }
  },
  
  setGhosted: function(isGhosted) {
    this.isGhosted = isGhosted;
    this.element[isGhosted ? 'addClassName' : 'removeClassName']('ghosted');
    if (isGhosted) {
      this.element.setValue(this.title);
    }    
  },

  // Hook into the enclosing form's `onsubmit` event so that we clear any
  // ghosted text before the form is sent.
  //
  // TODO: Wrap Prototype's serialization logic so that this applies to Ajax
  // form submission as well.
  onSubmit: function() {
    if (this.isGhosted) {
      this.element.setValue('');
    }
  }
});

document.observe("dom:loaded", function() {
  $$('label.ghosted').each( function(label) {
    var text = label.innerHTML, input = $(label.readAttribute('for'));
    new Form.GhostedField(input, text, { cloak: true });
  });
});

document.observe("dom:loaded", function() {
  var commentsSection = $(document.body).down('div.comments-section');
  if (commentsSection)
    Comments.attributeBlockQuotes(commentsSection);
});

document.observe("preview:updated", function() {
  Comments.attributeBlockQuotes($('comment_preview'));
});

document.observe("dom:loaded", function() {
  $$('small.comment-quote-link > a').each( function(a) {
    a.observe('click', Comments.quote.bind(Comments));
  });
});

document.observe("dom:loaded", function() {
  if ($('convert_code')) {
    $('convert_code').observe('click',
     Comments.convertSelectionToCode.bind(Comments));    
  }
});

document.observe('dom:loaded', function() {
  if ($(document.body).down('#comment_form textarea')) {
    window.$previewer = new Comments.Previewer($('comment_preview'), $('comment_form'));
  }
});

document.observe("dom:loaded", function() {
  
  if (!$('openid_checkbox')) return;
  
  var containerOpenId = $('post_comment').down('div.post-comment-login-openid');
  var containerNormal = $('post_comment').down('div.post-comment-login-normal');
  
  function hideOrShow(element, shouldShow) {
    shouldShow ? element.show() : element.hide();
  }

  $('openid_checkbox').observe('click', function(event) {
    var isChecked = event.element().checked;
    
    hideOrShow(containerNormal, !isChecked);
    hideOrShow(containerOpenId,  isChecked);    
  });
});












