'use strict';

var compact     = require('es5-ext/lib/Array/prototype/compact')
  , replace     = require('es5-ext/lib/String/prototype/simple-replace')
  , memoize     = require('memoizee')
  , promisify   = require('deferred').promisify
  , resolve     = require('path').resolve
  , readFile    = promisify(require('fs').readFile)
  , writeFile   = promisify(require('fs').writeFile)
  , getSnapshot = require('../lib/history')._snapshot

  , metaNames = { $construct: true, validateConstruction: true, toString: true }
  , stringify = JSON.stringify, getTpl;

getTpl = memoize(function () {
	return readFile(resolve(__dirname, 'tagger.tpl'), 'utf8');
});

module.exports = function (filename, tag/*, options*/) {
	var options = Object(arguments[2]);
	tag = String(tag);
	return writeFile(resolve(String(filename)), getTpl()(function (tpl) {
		var data = getSnapshot(), done = {};
		if (options.log) tpl = tpl.replace(/\/\/\$LOG\$/g, '');
		tpl = tpl.replace('$TAG$', stringify(tag).slice(1, -1));
		tpl = tpl.replace('$TIME$', (new Date()).toISOString());
		data = compact.call(data.map(function (event) {
			var obj = event.obj;
			if (obj._type_ !== 'relation') return null;
			while (obj.obj && (obj.obj._type_ === 'relation')) obj = obj.obj;
			if (obj.obj._type_ !== 'prototype') return null;
			if (obj.obj.ns._childType_ !== 'object') return null;
			if (metaNames.hasOwnProperty(obj.name)) return null;
			if (done.hasOwnProperty(obj._id_)) return null;
			done[obj._id_] = true;
			return 'getObject(' + stringify(obj._id_) + ').tags.add(' +
				stringify(tag) + ');';
		}));
		tpl = tpl.replace('$COUNT$', data.length);
		return replace.call(tpl, '$CONTENT$', data.join('\n'));
	}));
};

@@ -15,73 +15,8 @@
 %0Avar
- compact     = require('es5-ext/lib/Array/prototype/compact')%0A  ,
  rep
@@ -373,89 +373,8 @@
 ot%0A%0A
-  , metaNames = %7B $construct: true, validateConstruction: true, toString: true %7D%0A
   , 
@@ -607,16 +607,26 @@
 %0A%09tag = 
+stringify(
 String(t
@@ -628,16 +628,17 @@
 ing(tag)
+)
 ;%0A%09retur
@@ -739,16 +739,28 @@
 one = %7B%7D
+, lines = %5B%5D
 ;%0A%09%09if (
@@ -840,30 +840,19 @@
 $TAG$', 
-stringify(
 tag
-)
 .slice(1
@@ -928,32 +928,16 @@
 data
- = compact.call(data.map
+.forEach
 (fun
@@ -987,74 +987,86 @@
 if (
-obj._type_ !== 'relation') return null;%0A%09%09%09while (obj.obj && (obj.
+done.hasOwnProperty(obj._id_)) return null;%0A%09%09%09done%5Bobj._id_%5D = true;%0A%09%09%09if ((
 obj.
@@ -1091,30 +1091,11 @@
 on')
-) obj = obj.obj;%0A%09%09%09if
+ &&
  (ob
@@ -1111,158 +1111,95 @@
 pe_ 
-!
+=
 == '
-prototype') return null;%0A%09%09%09if (obj.obj.ns._childType_ !== 'object') return null;%0A%09%09%09if (metaNames.hasOwnProperty(obj.name)) return null;%0A
+relation') &&%0A%09%09%09%09%09((obj.name === 'ns') %7C%7C (obj.name === 'required'))) %7B%0A%09
 %09%09%09if (
+!
 done
@@ -1218,36 +1218,31 @@
 rty(obj.
+obj.
 _id_)) 
-return null;%0A
+%7B%0A%09%09
 %09%09%09done%5B
@@ -1237,32 +1237,36 @@
 %7B%0A%09%09%09%09%09done%5Bobj.
+obj.
 _id_%5D = true;%0A%09%09
@@ -1266,23 +1266,29 @@
 rue;%0A%09%09%09
-return 
+%09%09lines.push(
 'getObje
@@ -1304,24 +1304,28 @@
 ringify(obj.
+obj.
 _id_) + ').t
@@ -1344,36 +1344,122 @@
 %09%09%09%09
-stringify(tag) + 
+%09%09tag + ');');%0A%09%09%09%09%7D%0A%09%09%09%7D%0A%09%09%09lines.push('getObject(' + stringify(obj._id_) + ').tags.add(' + tag +%0A%09%09%09%09
 ');'
+)
 ;%0A%09%09%7D)
-)
 ;%0A%09%09
@@ -1541,20 +1541,21 @@
 TENT$', 
-data
+lines
 .join('%5C

Tag all objects with tagger.