/*  postEditor, version 1.0: http://icebeat.bitacoras.com
 *  Daniel Mota aka IceBeat <daniel.mota@gmail.com>
/*--------------------------------------------------------------------------*/

/*
Markdown
*/
var snippets = {
  "1" : ['# ','',''],
  "2" : ['## ','',''],
  "3" : ['### ','',''],
  "4" : ['#### ','',''],
  "5" : ['##### ','',''],
  "6" : ['###### ','',''],
  "s" : ['*','','*'],
  "e" : ['_','','_'],
  "a" : ['[','texto',']'],
  "[" : ['[','texto',']'],
  "." : [".\n* ",'',''],
  "i" : ['![','alt texto',']'],
  "]" : ['](http://','site.com',' "")']
};

var smartTypingPairs = {
  '"' : '"',
  '(' : ')',
  '{' : '}',
  '[' : ']',
  "<" : ">",
  "'" : "'"
};

var postEditor = new Class({
  tab:"    ",
  initialize: function(e,snippets,pairs) {
    if(window.ActiveXObject) return;
    this.e = $(e);
    this.snippets = snippets || {};
    this.pairs = pairs || {};
    this.styles = {
		  line_height: this.e.getStyle('line-height').toInt() || 14,
		  font_size: this.e.getStyle('font-size').toInt() || 11,
		  height: this.e.getStyle('height').toInt()
		};
		this.e.onkeypress = this.onKeyPress.bind(this);
  },
  changeSnippets: function(snippets) {
    this.snippets = snippets || {};
  },
  ss: function() {
    return this.e.selectionStart;
  },
  se: function() {
    return this.e.selectionEnd;
  },
  getStart: function(rest) {
		var rest = rest ? rest.length : 0;
		return this.e.value.slice(0,this.ss()-rest);
	},
	getEnd: function() {
		return this.e.value.slice(this.se());
	},
	selectRange: function(start,end) {
		this.e.selectionStart = start;
		this.e.selectionEnd = start+end;
	},
  updateScroll: function() {
	  var txt = this.getStart(),
		lines = txt.split("\n"),
		nlines = lines.length,
		height = (nlines-Math.round(this.e.scrollTop/this.styles.line_height))*this.styles.line_height,
		height = height+this.styles.line_height;
		if(height>=this.styles.height)
		  this.e.scrollTop += this.styles.line_height;
		this.scrollTop = this.e.scrollTop;
    this.scrollLeft = this.e.scrollLeft;
    this.e.focus();
	},
	onKeyPress: function(e) {
	  var charCode = String.fromCharCode(e.charCode);
	  if(this.pairs[charCode]) {
	    this.autoclosing(e,charCode,this.pairs[charCode]);
	    return true;
	  }
    var fn = null;
    if(e.keyCode==13 || e.keyCode==9 || e.keyCode==8 || e.keyCode==46) {
      fn=true;
      this.scrollTop = this.e.scrollTop;
      this.scrollLeft = this.e.scrollLeft;
    }
    switch(e.keyCode) {
      case 13:  this.onEnter(e);    break;
	    case  9:  this.onTab(e);      break;
		  case  8:  this.onBackspace(e);break;
		  case 46:  this.onDelete(e);   break;
		}
		if(fn) {
		  this.e.scrollTop = this.scrollTop;
		  this.e.scrollLeft = this.scrollLeft;
		  this.e.focus();
	  }
  },
  onEnter: function(e) {
    this.updateScroll();
    var ss = this.ss(), se = this.se();
    if(ss==se) {
      var pre = this.getStart(),
          lines = pre.split("\n"),
          line = lines.pop(),
          tab = line.match(/^\s+/gi);
      if(tab) {
          e.preventDefault();
          tab = tab.join();
          this.e.value = pre.concat("\n"+tab).concat(this.getEnd());
          this.selectRange(ss+1+tab.length,0);
      }
    }
  },
  onTab: function(e) {
    e.preventDefault();
    var ss = this.ss(), se = this.se(), txt = this.getStart();
    if (ss != se && this.e.value.slice(ss,se).indexOf("\n") != -1) {
        var sel = this.e.value.slice(ss,se),
            seln = sel.split("\n").length,
            newsel = sel.replace(/\n/g,"\n"+this.tab);
        this.e.value = txt.concat(this.tab).concat(newsel).concat(this.getEnd());
        this.selectRange(ss + 4,se + (4*seln) - ss - 4);
    } else {
        var snippetObj = null;
        for (var key in this.snippets) {
          var value = this.snippets[key];
          if (typeof value == 'function') continue;
          if(txt.length-key.length==-1) continue;
          if($type(value)=='array') value={snippet:value};
				  if(txt.length-key.length==txt.lastIndexOf(key)) {
				    snippetObj = value;
				    break;
				  }
        }
        if(snippetObj && (!snippetObj.scope || this.scope(snippetObj.scope))) {
            var start = this.getStart(key), snippet = Object.extend({},snippetObj.snippet),
            line = txt.split("\n").pop(), tab = line.match(/^\s+/gi);
            if(tab) {
              tab = tab.join();
              snippet[0]= snippet[0].replace(/\n/g,"\n"+tab);
              snippet[1]= snippet[1].replace(/\n/g,"\n"+tab);
              snippet[2]= snippet[2].replace(/\n/g,"\n"+tab);
            }
        	  this.e.value = start+snippet[0]+snippet[1]+snippet[2]+this.getEnd();
        	  this.selectRange(start.length+snippet[0].length,snippet[1].length);
        	  snippet = null;
        } else {
          this.e.value = txt.concat(this.tab).concat(this.e.value.slice(ss,this.e.value.length));
          if (ss == se) this.selectRange(ss + 4,0);
          else this.selectRange(ss + 4,se - ss);
        }
    }
  },
  onBackspace: function(e) {
    var ss = this.ss(), se = this.se();
    if(ss == se && this.e.value.slice(ss - 4,ss) == this.tab) {
			e.preventDefault();
			var start = this.getStart(this.tab);
			if(start.match(/\n$/g)) {
        this.selectRange(ss - 4,0);
      } else {
        this.e.value = this.getStart(this.tab).concat(this.e.value.slice(ss,this.e.value.length));
        this.selectRange(ss - 4,0);
      }
		} else if(ss == se) {
  		  var charCode = this.e.value.slice(ss - 1,ss), close = this.e.value.slice(ss,ss+1), pair = this.pairs[charCode];
  		  if($type(pair)=='string') pair={'pair':pair};
  		  if(pair && pair.pair == close) {
  		    this.e.value = this.getStart(pair.pair).concat(this.e.value.slice(ss,this.e.value.length));
          this.selectRange(ss,0);
  		  }
  	}
  },
  onDelete: function(e) {
    var ss = this.ss(), se = this.se();
    if(ss == se && this.e.value.slice(ss,ss+4) == this.tab) {
			e.preventDefault();
      this.e.value = this.getStart().concat(this.e.value.slice(ss+4,this.e.value.length));
      this.selectRange(ss,0);
		}
  },
  autoclosing: function(e,open,pair) {
    if($type(pair)=='string') pair={'pair':pair};
    if(!pair.scope || this.scope(pair.scope)) {
      var ss = this.ss(), se = this.se(), start = this.getStart();
      if(ss == se) {
        this.e.value = start+pair.pair+this.getEnd();
        this.selectRange(start.length,0);
      } else {
        e.preventDefault();
        var sel = this.e.value.slice(ss,se);
        this.e.value = start.concat(open+sel+pair.pair).concat(this.getEnd());
        this.selectRange(ss+1,se-ss);
      }
    }
  },
  scope: function(scopes) {
    var ss = this.ss(),txt = this.getStart();
    for (var key in scopes) {
      if(!key) return true;
      var open = txt.lastIndexOf(key);
      if(open > -1) {
        var newtxt = this.e.value.slice(open+key.length,ss);
        var close = newtxt.lastIndexOf(scopes[key]);
        if(close == -1) return true;
      }
    }
    return false;
  }
});