$(document).ready(function() {
  
  var terminal = (function() {
    
    var _max_history = 100;
    
    var _has_local_storage = (function() {
      var b = false;
      /**
       * The main reason we use try / catch is because despite Firefox 
       *   supporting it, it can be disabled in your about:config settings 
       *   and an error will be thrown
       * @see http://www.dustindiaz.com/javascript-cache-provider/
       */
      try {
        b = (('localStorage' in window) && window['localStorage'] !== null);
      } catch(e) {
        // TODO: if exception, it's already false, so who cares.
      }
      return function() {
        return b;
      };
    })();
    
    var _constants = {
      HISTORY_DIRECTION_UP   : "up",
      HISTORY_DIRECTION_DOWN : "down",
      KEY_STORAGE            : "yz.labs.shell"
    };
    
    var _ascii_art = {
      'starwars' : [
        '      ________________.  ___     .______               ',
        '     /                | /   \\    |   _  \\            ',
        '    |   (-----|  |----`/  ^  \\   |  |_)  |            ',
        '     \\   \\    |  |    /  /_\\  \\  |      /          ',
        '.-----)   |   |  |   /  _____  \\ |  |\\  \\-------.   ',
        '|________/    |__|  /__/     \\__\\| _| `.________|    ',
        ' ____    __    ____  ___     .______    ________.      ',
        ' \\   \\  /  \\  /   / /   \\    |   _  \\  /        | ',
        '  \\   \\/    \\/   / /  ^  \\   |  |_)  ||   (-----`  ',
        '   \\            / /  /_\\  \\  |      /  \\   \\      ',
        '    \\    /\\    / /  _____  \\ |  |\\  \\---)   |     ',
        '     \\__/  \\__/ /__/     \\__\\|__| `._______/       '
      ],
      'finger' : [
        '...................../´¯/)             ',
        '...................,/¯../              ',
        '.................../..../              ',
        '............./´¯/\'...\'/´¯¯`·¸        ',
        '........../\'/.../..../......./¨¯\\    ',
        '........(\'(...´...´.... ¯~/\'...\')   ',
        '.........\\.................\'...../   ',
        '..........\'\'...\\.......... _.·´     ',
        '............\\..............(          ',
        '.............\\.............\\...      '
      ],
      'unicorn' : [
        '                                /      ',
        '                     __       //       ',
        '                     -\\= \\=\\ //     ',
        '                   --=_\\=---//=--     ',      
        '                 -_==/  \\/ //\\/--    ',   
        '                  ==/   /0   0\\==--   ', 
        '     _ _ _ _     /_/    \\  ]  /--     ',
        '    /\\ ( (- \\    /       ] ] ]==-    ',
        '   (\\ _\\_\\_\\-\\__/     \\  (,_,)-- ', 
        '  (\\_/                 \\     \\-     ',
        '  \\/      /       (   ( \\  ] /)      ', 
        '  /      (         \\   \\_ \\./ )     ',  
        '  (       \\         \\      )  \\     ', 
        '  (       /\\_ _ _ _ /---/ /\\_  \\    ', 
        '   \\     / \\     / ____/ /   \\  \\  ',  
        '    (   /   )   / /  /__ )   (  )      ', 
        '    (  )   / __/ \'---\'       / /     ',
        '   \\  /   \\ \\             _/ /      ', 
        '    ] ]     )_\\_         /__\\/       ', 
        '    /_\\     ]___\\                    ', 
        '   (___)                               '
      ]
    };
  
    var _cmd_windows = function() {
      return arguments[0].join(' ') + ": Microsoft not found";
    }
  
    var _cmd_unimplemented = function() {
      return arguments[0].join(' ') + ": Unimplemented feature.";
    }

    var _location = '/';

    var _storage = {
      persist : function(data) {
        return false;
        if (_has_local_storage() && yz.JSON) {
          window.localStorage[_constants.KEY_STORAGE] = yz.JSON.stringify(data);
          return true;
        }
        return false;
      },
      get : function() {
        if (_has_local_storage() && yz.JSON) {
          try {
            var data = window.localStorage[_constants.KEY_STORAGE];
            return JSON.parse(data) || null;
          } catch(e) {
            
          }
        }
        return null;
      }
    }
    
    // initialize
    var _history = _storage.get() || [];
    var _cursor = _history.length;

    var _getCursor = function() {
      return _cursor;
    }
  
    var _setCursor = function(direction) {
      if (direction === _constants.HISTORY_DIRECTION_UP) {
        _cursor = (_getCursor() < 1) ? 0 : _cursor-1;
      } else if (direction === _constants.HISTORY_DIRECTION_DOWN){
        _cursor = (_getCursor() > _history.length) ? _history.length : _cursor+1;
      }
    }
   
    var _getHistoryValue = function(direction) {
      return _history[_getCursor(_setCursor(direction))];
    }
  
    var _getLocation = function() {
      return _location;
    }
  
    var _setLocation = function() {
    
    }

    var _wrapTag = function(str,tag) {
      return '<'+tag+'>' + str + '</'+tag+'>';
    }

    var _execute = function(cmd) {
      var value = null,
          cmds = cmd.split(' ');
      if (_cmds[cmds[0]]) {
        if (typeof _cmds[cmds[0]] === "function") {
          value = _cmds[cmds[0]](cmds);
        } else {
          value = _cmds[cmds[0]];
        }
      }  
      _history.push(cmd);
      if (_history.length > _max_history) {
        _history.shift();
      }
      _storage.persist(_history);
      _cursor = _history.length;
      return value;
    }
  
    var _cmds = {
      'logout'      : "Where you rushing to?",
      'exit'        : "There is no escape.",
      'ls'          : _cmd_unimplemented,
      'cd'          : _setLocation,
      'pwd'         : "Where you at?",
      'cat'         : "Da cutest distractshun of da decaid? Y, lolcats of corse! We can neber haz enuf of deez capshioned pics of cuddlie kittehs.",
      'more'        : "MOAR MOAR MOAR!",
      'less'        : "LESS LESSER LESSEST!",
      'finger'      : function() { return _wrapTag(_ascii_art['finger'].join('\n'),'pre') },
      'mkdir'       : "",
      'rmdir'       : "",
      'rm -rf'      : "",
      'less'        : "",
      'vi'          : "",
      'vim'         : "",
      'pico'        : "",
      'emacs'       : "",
      'pine'        : "You want some?",
      'elm'         : "",
      'tail'      : "",
      'telnet'    : "",
      'ssh'       : "",
      'rlogin'    : "",
      'passwd'    : "",
      'history'     : function() { return _wrapTag(_history.join('\n'),'pre'); },
      'whoami'      : "Yeah, who the fuck are you?",
      'man'         : "What manual page do you want?",
      'date'        : function() { return new Date().toString(); },
      'browser'     : function() { return navigator.appName + " " + navigator.userAgent; },
      'apt-get'     : function(args) {
        if (args[1] && _ascii_art[args[1]]) {
          return (_wrapTag(_ascii_art[args[1]].join('\n'),'pre'))
        }
        if (args[1]) {
          return args[0] + " " + args[1] + ": package not found";
        }
        return args[0] + " what?";
      },
      'clear'        : "",
      'lol'          : "What's so funny?",
      'dir'          : _cmd_windows,
      '' : ""                      
    };
  
    return {
      constants : _constants,
      getHistoryValue : _getHistoryValue,
      execute: _execute
    };
  
  })();
  
  $('#shell-pane').bind('click', function(event){
      $(this).find('input').focus();
    }).find('input').bind('keyup', function(event){
      var key = event.which,
          val = $.trim($(this).val()),
          result;
      // enter
      if ("13" == key && val) {
        try {
          if (val === "clear") {
            $(this).parent().find('ul').empty();
          } else {
            result = terminal.execute(val);
            if (!result) {
              result = val + ": command not found";
            }
            $(this).parent().find('ul').append('<li>'+($(this).prev().html())+' '+val+'</li><li>'+result+'</li>');
          }
        } catch(e) {
          //TODO: exception handling
        } finally {
          $(this).val('');
        }
      // arrow up
      } else if ("38" == key) {
        var value = terminal.getHistoryValue(terminal.constants.HISTORY_DIRECTION_UP);
        $(this).val(value);
      // down up
      } else if ("40" == key) {
        var value = terminal.getHistoryValue(terminal.constants.HISTORY_DIRECTION_DOWN);
        $(this).val(value);
      // tab
      } else if ("9" == key) {
        
      }
  }).val('').focus().parents("form").bind('submit',function(event){ return false; });
});
