var texteditor = Object.copy(inputpanel, {
  title: "text editor",
  wh: [700,500],
  _cursor:0, /* Text cursor: [char,line] */
  get cursor() { return this._cursor; },
  set cursor(x) {
    if (x > this.value.length)
      x = this.value.length;
    if (x < 0)
      x = 0;
      
    this._cursor = x;
    this.line = this.get_line();
  },

  submit() {},

  line: 0,
  killring: [],
  undos: [],
  startbuffer: "",

  savestate() {
    this.undos.push(this.value.slice());
  },

  popstate() {
    if (this.undos.length === 0) return;
    this.value = this.undos.pop();
    this.cursor = this.cursor;
  },

  copy(start, end) {
    return this.value.slice(start,end);
  },

  delete_line(p) {
    var ls = this.line_start(p);
    var le = this.line_end(p)+1;
    this.cut_span(ls,le);
    this.to_line_start();
  },

  line_blank(p) {
    var ls = this.line_start(p);
    var le = this.line_end(p);
    var line =  this.value.slice(ls, le);
    if (line.search(/[^\s]/g) === -1)
      return true;
    else
      return false;
  },

  get_line() {
    var line = 0;
    for (var i = 0; i < this.cursor; i++)
      if (this.value[i] === "\n")
        line++;

    return line;
  },

  start() {
    this.cursor = 0;
    this.startbuffer = this.value.slice();
  },

  get dirty() {
    return this.startbuffer !== this.value;
  },

  src: "NEW FILE",

  guibody() {
    return [
      Mum.text({str:`EDITING ${this.src}`}),
      Mum.text({str:this.value, caret:this.cursor, offset:[0,-16]}),
    ];
  },

  insert_char(char) {
    this.value = this.value.slice(0,this.cursor) + char + this.value.slice(this.cursor);
    this.cursor++;
  },

  line_starting_whitespace(p) {
    var white = 0;
    var l = this.line_start(p);

    while (this.value[l] === " ") {
      white++;
      l++;
    }

    return white;
  },

  cut_span(start, end) {
    if (end < start) return;
    this.savestate();
    var ret = this.value.slice(start,end);
    this.value = this.value.slice(0,start) + this.value.slice(end);
    if (start > this.cursor)
      return ret;
      
    this.cursor -= ret.length;
    return ret;
  },

  next_word(pos) {
    var v = this.value.slice(pos+1).search(/[^\w]\w/g);
    if (v === -1) return pos;
    return pos + v + 2;
  },

  prev_word(pos) {
    while (this.value.slice(pos,pos+2).search(/[^\w]\w/g) === -1 && pos > 0)
      pos--;

    return pos+1;
  },

  end_of_word(pos) {
    var l = this.value.slice(pos).search(/\w[^\w]/g);
    return l+pos;
  },

  get inset() {
    return this.cursor - this.value.prev('\n', this.cursor) - 1;
  },

  line_start(p) {
    return this.value.prev('\n', p)+1;
  },

  line_end(p) {
    return this.value.next('\n', p);
  },

  next_line(p) {
    return this.value.next('\n',p)+1;
  },

  prev_line(p) {
    return this.line_start(this.value.prev('\n', p));
  },

  to_line_start() {
    this.cursor = this.value.prev('\n', this.cursor)+1;
  },

  to_line_end() {
    var p = this.value.next('\n', this.cursor);
    if (p === -1)
      this.to_file_end();
    else
      this.cursor = p;
  },

  line_width(pos) {
    var start = this.line_start(pos);
    var end = this.line_end(pos);
    if (end === -1)
      end = this.value.length;

    return end-start;
  },

  to_file_end() { this.cursor = this.value.length; },

  to_file_start() { this.cursor = 0; },

  desired_inset: 0,
});

texteditor.inputs = {};

texteditor.inputs.char = function(char) {
  this.insert_char(char);
  this.keycb();
},

texteditor.inputs.enter = function(){
  var white = this.line_starting_whitespace(this.cursor);
  this.insert_char('\n');

  for (var i = 0; i < white; i++)
    this.insert_char(" ");
};
texteditor.inputs.enter.rep = true;

texteditor.inputs.backspace = function(){
  this.value = this.value.slice(0,this.cursor-1) + this.value.slice(this.cursor);
  this.cursor--;
};
texteditor.inputs.backspace.rep = true;


texteditor.inputs['C-s'] = function() {
  if (this.srctype === 'function') {
    eval(`${this.src} = ${this.value}`);
  }
};
texteditor.inputs['C-s'].doc = "Save edited text.";

texteditor.inputs['C-u'] = function() { this.popstate(); };
texteditor.inputs['C-u'].doc = "Undo.";

texteditor.inputs['C-q'] = function() {
  var ws = this.prev_word(this.cursor);
  var we = this.end_of_word(this.cursor)+1;
  var find = this.copy(ws, we);
  var obj = editor.edit_level.varname2obj(find);

  if (obj) {
    editor.unselect();
    editor.selectlist.push(obj);
  }
};
texteditor.inputs['C-q'].doc = "Select object of selected word.";

texteditor.inputs['C-o'] = function() {
  this.insert_char('\n');
  this.cursor--;
};
texteditor.inputs['C-o'].doc = "Insert newline.";
texteditor.inputs['C-o'].rep = true;

texteditor.inputs['M-o'] = function() {
  while (this.line_blank(this.next_line(this.cursor)))
    this.delete_line(this.next_line(this.cursor));

  while (this.line_blank(this.prev_line(this.cursor)))
    this.delete_line(this.prev_line(this.cursor));
};
texteditor.inputs['M-o'].doc = "Delete surround blank lines.";

texteditor.inputs['C-d'] = function () { this.value = this.value.slice(0,this.cursor) + this.value.slice(this.cursor+1); };
texteditor.inputs['C-d'].doc = "Delete character.";

texteditor.inputs['M-d'] = function() { this.cut_span(this.cursor, this.end_of_word(this.cursor)+1); };
texteditor.inputs['M-d'].doc = "Delete word.";

texteditor.inputs['C-a'] = function() {
  this.to_line_start();
  this.desired_inset = this.inset;
};
texteditor.inputs['C-a'].doc = "To start of line.";

texteditor.inputs['C-y'] = function() {
  if (this.killring.length === 0) return;
  this.insert_char(this.killring.pop());
};
texteditor.inputs['C-y'].doc = "Insert from killring.";

texteditor.inputs['C-e'] = function() {
  this.to_line_end();
  this.desired_inset = this.inset;
};
texteditor.inputs['C-e'].doc = "To line end.";

texteditor.inputs['C-k'] = function() {
  if (this.cursor === this.value.length-1) return;
  var killamt = this.value.next('\n', this.cursor) - this.cursor;
  var killed = this.cut_span(this.cursor-1, this.cursor+killamt);
  this.killring.push(killed);
};
texteditor.inputs['C-k'].doc = "Kill from cursor to end of line.";

texteditor.inputs['M-k'] = function() {
  var prevn = this.value.prev('\n', this.cursor);
  var killamt = this.cursor - prevn;
  var killed = this.cut_span(prevn+1, prevn+killamt);
  this.killring.push(killed);
  this.to_line_start();
};
texteditor.inputs['M-k'].doc = "Kill entire line the cursor is on.";

texteditor.inputs['C-b'] = function() {
  this.cursor--;
  this.desired_inset = this.inset;
};
texteditor.inputs['C-b'].rep = true;
texteditor.inputs['M-b'] = function() {
  this.cursor = this.prev_word(this.cursor-2);
  this.desired_inset = this.inset;
};
texteditor.inputs['M-b'].rep = true;

texteditor.inputs['C-f'] = function() {
  this.cursor++;
  this.desired_inset = this.inset;
};
texteditor.inputs['C-f'].rep = true;
texteditor.inputs['M-f'] = function() {
  this.cursor = this.next_word(this.cursor);
  this.desired_inset = this.inset;
};
texteditor.inputs['M-f'].rep = true;

texteditor.inputs['C-p'] = function() {
  if (this.cursor === 0) return;
  this.desired_inset = Math.max(this.desired_inset, this.inset);
  this.cursor = this.prev_line(this.cursor);
  var newlinew = this.line_width(this.cursor);
  this.cursor += Math.min(this.desired_inset, newlinew);
};
texteditor.inputs['C-p'].rep = true;

texteditor.inputs['M-p'] = function() {
  while (this.line_blank(this.cursor))
    this.cursor = this.prev_line(this.cursor);

  while (!this.line_blank(this.cursor))
    this.cursor = this.prev_line(this.cursor);
};
texteditor.inputs['M-p'].doc = "Go up to next line with text on it.";
texteditor.inputs['M-p'].rep = true;

texteditor.inputs['C-n'] = function() {
  if (this.cursor === this.value.length-1) return;
  if (this.value.next('\n', this.cursor) === -1) {
    this.to_file_end();
    return;
  }

  this.desired_inset = Math.max(this.desired_inset, this.inset);
  this.cursor = this.next_line(this.cursor);
  var newlinew = this.line_width(this.cursor);
  this.cursor += Math.min(this.desired_inset, newlinew);
};
texteditor.inputs['C-n'].rep = true;

texteditor.inputs['M-n'] = function() {
  while (this.line_blank(this.cursor))
    this.cursor = this.next_line(this.cursor);

  while (!this.line_blank(this.cursor))
    this.cursor = this.next_line(this.cursor);
};
texteditor.inputs['M-n'].doc = "Go down to next line with text on it.";
texteditor.inputs['M-n'].rep = true;

texteditor.open_fn = function(fnstr)
{
  var fn = eval(fnstr);
  if (!fn) {
    Log.warn(`${fnstr} is not a function.`);
    return;
  }
  this.src = fnstr;
  this.srctype = "function";
  editor.openpanel(this);
  this.value = fn;
  this.cursor = 0;
}
