new object $connection: $network;

var $connection active = 0;
var $connection buffer = `[];
var $connection daemon = 0;
var $connection host = "";
var $connection interface = 0;
var $connection line_buffer = 0;
var $connection remote = 0;
var $connection local = 0;
var $connection port = 0;
var $connection read_block = [];
var $connection started_at = 0;
var $root inited = 1;

public method .remote() {
    return remote;
};

public method .close() {
    (> .destroy() <);
};

public method .cwritef() {
    arg fname;
    
    (> cwritef(fname) <);
};

public method .daemon_shutdown() {
    var c;
    
    for c in (.children())
        (> c.close() <);
};

driver method .disconnect() {
    arg [args];

    (| .close() |);
};

public method .finish_reading_block() {
    var task_id, lines;
    
    task_id = read_block.task_id();
    lines = read_block.lines();
    read_block = 0;
    resume(task_id, lines);
};

root method .init_connection() {
    buffer = `[];
    host = "";
    line_buffer = [];
};

public method .interface() {
    return interface;
};

public method .is_reading_block() {
    return read_block ? 1 | 0;
};

public method .new() {
  arg @args;
  var child;

  // args are remote_ip, local_ip, port
  active = time();
  child = .spawn();
  child.init(sender(), @args);
  return child;
};

public method .init() {
  arg @args;

  [remote, local, port] = args;
};

public method .parse() {
  arg incoming;
  var lines, line, index;

  // called by the driver when a connection receives data
  lines = ((buffer + incoming) + `[10]).break_lines();
  index = lines.length();
  buffer = lines[index];
  lines = lines.delete(index);
  line_buffer += lines;
  while (line_buffer) {
    line = line_buffer[1];
    line_buffer = line_buffer.delete(1);
    (| .parse_line(line) |);
  }
};

protected method .parse_line() {
  arg line;

  // Overload this!
  .debug("Parse line: " + line);
};


public method .write() {
    arg what, [how];
    var elem, sep;
    
    sep = ('non_terminated in how) ? `[] | `[10];
    switch (type(what)) {
        case 'string:
            what = $buffer.from_strings([what], sep);
        case 'list:
            what = $buffer.from_strings(what, sep);
        case 'buffer:
        default:
            throw(~type, "Write: strings, list of strings and buffers.");
    }
    cwrite(what);
};