//----------------------------------------------------------------------------
//  Copyright (C) 2008-2011  The IPython Development Team
//
//  Distributed under the terms of the BSD License.  The full license is in
//  the file COPYING, distributed as part of this software.
//----------------------------------------------------------------------------

//============================================================================
// TextCell
//============================================================================

var IPython = (function (IPython) {

    var utils = IPython.utils;
    // TextCell base class

    var TextCell = function (notebook, kernel) {
        this.kernel = kernel || null;
        this.code_mirror_mode = this.code_mirror_mode || 'htmlmixed';
        IPython.Cell.apply(this, arguments);
        this.rendered = false;
        this.cell_type = this.cell_type || 'text';
    };


    TextCell.prototype = new IPython.Cell();


    TextCell.prototype.create_element = function () {
        var cell = $("<div>").addClass('cell text_cell border-box-sizing');
        cell.attr('tabindex','2');
        var input_area = $('<div/>').addClass('text_cell_input border-box-sizing');
        var options = {
            indentUnit : 4,
            mode: this.code_mirror_mode,
            theme: 'default',
            value: this.placeholder,
            readOnly: this.read_only,
            lineWrapping : true,
            onKeyEvent: $.proxy(this.handle_codemirror_keyevent,this)
        };
        var keyMap = this.notebook ? this.notebook.keyMap : null;
        if (keyMap){
          options['keyMap'] = keyMap;
        }
        this.code_mirror = CodeMirror(input_area.get(0), options);
        // The tabindex=-1 makes this div focusable.
        var render_area = $('<div/>').addClass('text_cell_render border-box-sizing').
            addClass('rendered_html').attr('tabindex','-1');
        cell.append(input_area).append(render_area);
        this.element = cell;
    };


    TextCell.prototype.bind_events = function () {
        IPython.Cell.prototype.bind_events.apply(this);
        var that = this;
        this.element.keydown(function(event) {
          that.handle_keydown(event, that);
        });
        this.element.dblclick(function () {
            that.edit();
        });
    };

    TextCell.prototype.handle_keydown = function (event) {
        if (event.which === 13 && !event.shiftKey) {
            if (this.rendered) {
                this.edit();
                return false;
            };
        };
    };

    TextCell.prototype.handle_codemirror_keyevent = function (editor, event) {
        // This method gets called in CodeMirror's onKeyDown/onKeyPress
        // handlers and is used to provide custom key handling. Its return
        // value is used to determine if CodeMirror should ignore the event:
        // true = ignore, false = don't ignore.
        
        if (event.keyCode === 13 && (event.shiftKey || event.ctrlKey)) {
            // Always ignore shift-enter in CodeMirror as we handle it.
            return true;
        }
        return false;
    };


    TextCell.prototype.select = function () {
        IPython.Cell.prototype.select.apply(this);
        var output = this.element.find("div.text_cell_render");
        output.trigger('focus');
    };


    TextCell.prototype.unselect = function() {
        // render on selection of another cell
        this.render();
        IPython.Cell.prototype.unselect.apply(this);
    };


    TextCell.prototype.edit = function () {
        if ( this.read_only ) return;
        if (this.rendered === true) {
            var text_cell = this.element;
            var output = text_cell.find("div.text_cell_render");  
            output.hide();
            text_cell.find('div.text_cell_input').show();
            this.code_mirror.refresh();
            this.code_mirror.focus();
            // We used to need an additional refresh() after the focus, but
            // it appears that this has been fixed in CM. This bug would show
            // up on FF when a newly loaded markdown cell was edited.
            this.rendered = false;
            if (this.get_text() === this.placeholder) {
                this.set_text('');
                this.refresh();
            }
        }
    };


    // Subclasses must define render.
    TextCell.prototype.render = function () {};


    TextCell.prototype.get_text = function() {
        return this.code_mirror.getValue();
    };


    TextCell.prototype.set_text = function(text) {
        this.code_mirror.setValue(text);
        this.code_mirror.refresh();
    };


    TextCell.prototype.get_rendered = function() {
        return this.element.find('div.text_cell_render').html();
    };


    TextCell.prototype.set_rendered = function(text) {
        this.element.find('div.text_cell_render').html(text);
    };


    TextCell.prototype.at_top = function () {
        if (this.rendered) {
            return true;
        } else {
            return false;
        }
    };


    TextCell.prototype.at_bottom = function () {
        if (this.rendered) {
            return true;
        } else {
            return false;
        }
    };


    TextCell.prototype.fromJSON = function (data) {
        IPython.Cell.prototype.fromJSON.apply(this, arguments);
        if (data.cell_type === this.cell_type) {
            if (data.source !== undefined) {
                this.set_text(data.source);
                // make this value the starting point, so that we can only undo
                // to this state, instead of a blank cell
                this.code_mirror.clearHistory();
                this.set_rendered(data.rendered || '');
                this.rendered = false;
                this.render();
            }
        }
    };


    TextCell.prototype.toJSON = function () {
        var data = IPython.Cell.prototype.toJSON.apply(this);
        data.cell_type = this.cell_type;
        data.source = this.get_text();
        return data;
    };

    // Kernel related calls.

    TextCell.prototype.set_kernel = function (kernel) {
        this.kernel = kernel;
    }

    TextCell.prototype.execute = function () {
        this.element.addClass("running");
        var callbacks = {
            'execute_reply': $.proxy(this._handle_execute_reply, this),
            'output': $.proxy(this.handle_output, this),
            //'clear_output': $.proxy(this.output_area.handle_clear_output, this.output_area),
            //'set_next_input': $.proxy(this._handle_set_next_input, this)
        };
        var msg_id = this.kernel.execute(this.get_code(), callbacks, {silent: false});
    };

    TextCell.prototype.convert_mime_types = IPython.OutputArea.prototype.convert_mime_types

    TextCell.prototype.handle_output = function (msg_type, content) {
        var json = {};
        json.output_type = msg_type;
        if (msg_type === "stream") {
            json.text = content.data;
            json.stream = content.name;
        } else if (msg_type === "display_data") {
            json = this.convert_mime_types(json, content.data);
        } else if (msg_type === "pyout") {
            json.prompt_number = content.execution_count;
            json = this.convert_mime_types(json, content.data);
        } else if (msg_type === "pyerr") {
            json.ename = content.ename;
            json.evalue = content.evalue;
            json.traceback = content.traceback;
        };
        // set the rendered
        if (json.output_type == 'pyout') {
          text = json.text
          text = eval(text)
          var html = IPython.markdown_converter.makeHtml(text);
          this.set_rendered(html);
          this.typeset()
        }
    };

    TextCell.prototype.get_code = function () {
      var cell = this;
      var code = cell.get_text();
      code = '"""'+code+'""".format(**locals())'
      return code
    };

    // HTMLCell

    var HTMLCell = function (notebook) {
        this.placeholder = "Type <strong>HTML</strong> and LaTeX: $\\alpha^2$";
        IPython.TextCell.apply(this, arguments);
        this.cell_type = 'html';
    };


    HTMLCell.prototype = new TextCell();


    HTMLCell.prototype.render = function () {
        if (this.rendered === false) {
            var text = this.get_text();
            if (text === "") { text = this.placeholder; }
            this.set_rendered(text);
            this.typeset();
            this.element.find('div.text_cell_input').hide();
            this.element.find("div.text_cell_render").show();
            this.rendered = true;
        }
    };


    // MarkdownCell

    var MarkdownCell = function (notebook) {
        this.placeholder = "Type *Markdown* and LaTeX: $\\alpha^2$";
        IPython.TextCell.apply(this, arguments);
        this.cell_type = 'markdown';
    };


    MarkdownCell.prototype = new TextCell();


    MarkdownCell.prototype.render = function () {
        if (this.rendered === false) {
            var text = this.get_text();
            if (text === "") { text = this.placeholder; }
            var html = IPython.markdown_converter.makeHtml(text);
            this.set_rendered(html);
            this.typeset()
            this.element.find('div.text_cell_input').hide();
            this.element.find("div.text_cell_render").show();
            var code_snippets = this.element.find("pre > code");
            code_snippets.replaceWith(function () {
                var code = $(this).html();
                /* Substitute br for newlines and &nbsp; for spaces
                   before highlighting, since prettify doesn't
                   preserve those on all browsers */
                code = code.replace(/(\r\n|\n|\r)/gm, "<br/>");
                code = code.replace(/ /gm, '&nbsp;');
                code = prettyPrintOne(code);

                return '<code class="prettyprint">' + code + '</code>';
            });
            this.rendered = true;
        }
    };


    // RawCell

    var RawCell = function (notebook) {
        this.placeholder = "Type plain text and LaTeX: $\\alpha^2$";
        this.code_mirror_mode = 'rst';
        IPython.TextCell.apply(this, arguments);
        this.cell_type = 'raw';
    };


    RawCell.prototype = new TextCell();


    RawCell.prototype.render = function () {
        this.rendered = true;
        this.edit();
    };


    RawCell.prototype.select = function () {
        IPython.Cell.prototype.select.apply(this);
        this.code_mirror.refresh();
        this.code_mirror.focus();
    };


    RawCell.prototype.at_top = function () {
        var cursor = this.code_mirror.getCursor();
        if (cursor.line === 0) {
            return true;
        } else {
            return false;
        }
    };


    RawCell.prototype.at_bottom = function () {
        var cursor = this.code_mirror.getCursor();
        if (cursor.line === (this.code_mirror.lineCount()-1)) {
            return true;
        } else {
            return false;
        }
    };


    // HTMLCell

    var HeadingCell = function (notebook) {
        this.placeholder = "Type Heading Here";
        IPython.TextCell.apply(this, arguments);
        this.cell_type = 'heading';
        this.level = 1;
    };


    HeadingCell.prototype = new TextCell();


    HeadingCell.prototype.fromJSON = function (data) {
        if (data.level != undefined){
            this.level = data.level;
        }
        IPython.TextCell.prototype.fromJSON.apply(this, arguments);
    };


    HeadingCell.prototype.toJSON = function () {
        var data = IPython.TextCell.prototype.toJSON.apply(this);
        data.level = this.get_level();
        return data;
    };


    HeadingCell.prototype.set_level = function (level) {
        this.level = level;
        if (this.rendered) {
            this.rendered = false;
            this.render();
        };
    };


    HeadingCell.prototype.get_level = function () {
        return this.level;
    };


    HeadingCell.prototype.set_rendered = function (text) {
        var r = this.element.find("div.text_cell_render");
        r.empty();
        r.append($('<h'+this.level+'/>').html(text));
    };


    HeadingCell.prototype.get_rendered = function () {
        var r = this.element.find("div.text_cell_render");
        return r.children().first().html();
    };


    HeadingCell.prototype.render = function () {
        if (this.rendered === false) {
            var text = this.get_text();
            if (text === "") { text = this.placeholder; }
            this.set_rendered(text);
            this.typeset();
            this.element.find('div.text_cell_input').hide();
            this.element.find("div.text_cell_render").show();
            this.rendered = true;
        };
    };

    IPython.TextCell = TextCell;
    IPython.HTMLCell = HTMLCell;
    IPython.MarkdownCell = MarkdownCell;
    IPython.RawCell = RawCell;
    IPython.HeadingCell = HeadingCell;


    return IPython;

}(IPython));

