var EOL = require('os').EOL
  , fs = require('fs')
  , assert = require('assert')
  , path = require('path')
  , util = require('util')
  , events = require('events');

var stores = {};

var HistoryStore = function(parent, options, lines) {
  options = options || {};
  console.dir(lines);
  lines = lines.split('\n');
  lines = lines.filter(function(line) {
    line = line.replace(/\r$/, '');
    line = line.trim();
    return line;
  })
  options.flush = options.flush !== undefined ? options.flush : true;
  options.duplicates = options.duplicates !== undefined
    ? options.duplicates : false;
  this.file = options.file;
  this.options = options;
  this._parent = parent;
  this._history = lines;
  //console.dir(lines);
  this._stream = fs.createWriteStream(this.file, {flags: 'a'});
  this._checkpoint = this._history.length;
}

HistoryStore.prototype.isFlushed = function() {
  return this._checkpoint === this._history.length;
}

HistoryStore.prototype.write = function(flush, cb) {
  var scope = this;
  if(!flush || this._checkpoint === this._history.length) return cb(null, scope);
  console.log('write to disc %s %s', this._checkpoint, this._history.length);
  var lines = this._history.slice(this._checkpoint, this._history.length);
  // add trailing newline
  if(lines[lines.length - 1]) {
    lines.push('');
  }
  var append = lines.join(EOL);
  console.log('write to disc %j', append);
  //this._stream =

}

HistoryStore.prototype.add = function(line, options, cb) {
  if(typeof options === 'function') {
    cb = options;
    options = null;
  }
  cb = typeof cb === 'function' ? cb : function noop(){};
  options = options || {};
  var scope = this
    , flush = options.flush || this.options.flush;
  if(!this.options.duplicates && ~this._history.indexOf(line)) {
    //console.log('ignoring duplicate');
    return cb(null, scope);
  }
  console.log('flush %s', flush);
  assert(typeof line === 'string', 'history entry must be a string')
  line = '' + line;
  line = line.replace(/\r?\n$/, '');
  this._history.push(line);
  this.write(flush, cb);
}

//HistoryStore.prototype.close = function

HistoryStore.prototype.clear = function(cb) {
  var scope = this;
  fs.writeFile(this.file, '', function(err) {
    if(err) return cb(err, scope);
    scope.history = [];
    scope.offset = 0;
    cb(null, scope);
  })
}

var History = function(options) {
  options = options || {};
  options.create = options.create !== undefined ? options.create : true;
  this.options = options;
}

util.inherits(History, events.EventEmitter);

History.prototype.load = function(options, cb) {
  var scope = this;
  if(typeof options === 'function') {
    cb = options;
    options = null;
  }
  options = options || {};
  var file = options.file || this.options.file
    , create = options.create !== undefined
      ? options.create : this.options.create;
  assert(file, 'cannot load history with no file');
  file = path.normalize(file);
  if(stores[file] && !options.force) {
    return cb(null, stores[file]);
  }
  function touch() {
    var st = fs.createWriteStream(file, function(err) {
      if(err) return cb(err, null, scope);
      st.end();
      st.destroy();
      load(options, cb);
    });
  }
  fs.readFile(file, function(err, contents) {
    if(err && err.code === 'ENOENT' && create) {
      return touch();
    }
    if(err) return cb(err, null, scope);
    var store = new HistoryStore(scope, scope.options, '' + contents);
    stores[file] = store;
    //console.log('isFlushed: %s', store.isFlushed());
    store.add('line item');
    store.add('line item');
    cb(null, store, scope);
  })
}

/**
 *  Get a history store by file path or all stores.
 */
History.prototype.getStore = function(file) {
  if(file) return stores[file];
  return stores;
}

function history(options, cb) {
  var h = new History(options);
  if(cb) {
    h.load(options, cb);
  }
  return h;
}

history.History = History;

module.exports = history;

@@ -265,30 +265,8 @@
 %7B%7D;%0A
-  console.dir(lines);%0A
   li
@@ -572,16 +572,85 @@
  false;%0A
+  options.limit = options.limit === 'number' ? options.limit : 2048;%0A
   this.f
@@ -751,28 +751,47 @@
 ;%0A  
-//console.dir(lines)
+this._checkpoint = this._history.length
 ;%0A  
@@ -856,51 +856,8 @@
 %7D);%0A
-  this._checkpoint = this._history.length;%0A
 %7D%0A%0AH
@@ -1111,24 +1111,26 @@
 , scope);%0A  
+//
 console.log(
@@ -1384,16 +1384,18 @@
 EOL);%0A  
+//
 console.
@@ -1429,18 +1429,16 @@
 end);%0A  
-//
 this._st
@@ -1441,18 +1441,135 @@
 ._stream
- =
+.write(append, function(err) %7B%0A    if(!err) scope._checkpoint = scope._history.length;%0A    return cb(err, scope);%0A  %7D);
 %0A%0A%7D%0A%0AHis
@@ -1928,49 +1928,8 @@
 ) %7B%0A
-    //console.log('ignoring duplicate');%0A
     
@@ -1958,16 +1958,18 @@
 ;%0A  %7D%0A  
+//
 console.
@@ -3584,112 +3584,186 @@
     
-//console.log('isFlushed: %25s', store.isFlushed());%0A    store.add('line item');%0A    store.add('line item'
+store.add('line item, random: ' + Math.random(), function(err, store) %7B%0A      //console.log('added item: %25s', store);%0A      console.log('isFlushed: %25s', store.isFlushed());%0A    %7D
 );%0A 

Add limit option.