require('classtool');
var hex = function(hex) {return new Buffer(hex, 'hex');};

function ClassSpec(b) {
	var fs = require('fs');
	var EncFile = require('./util/EncFile');
	var Address = require('./Address').class();
	var networks = require('./networks');
  	var util = b.util || require('./util/util');
	var ENC_METHOD = 'aes-256-cbc';

	var skeleton = {
		client: 'libcoin',
		client_version: '0.0.1',
		network: 'testnet',
		version: 1,
		best_hash: null,
		best_height: -1,
		keys: [],
		sin: {},
		scripts: {},
	};

	function Wallet(cfg) {
		if (typeof cfg !== 'object')
			cfg = {};

		// deep copy (no references)
		if (cfg.datastore)
			this.datastore = JSON.parse(JSON.stringify(cfg.datastore));
		else
			this.datastore = JSON.parse(JSON.stringify(skeleton));

		this.network = undefined;
		this.dirty = cfg.dirty || true;
	};

	Wallet.prototype.readSync = function(filename, passphrase) {
		this.datastore = EncFile.readJFileSync(ENC_METHOD,
						       passphrase, filename);
		this.dirty = false;
	};

	Wallet.prototype.writeSync = function(filename, passphrase) {
		var tmp_fn = filename + ".tmp";

		EncFile.writeJFileSync(ENC_METHOD, passphrase, tmp_fn,
				       this.datastore);
		fs.renameSync(tmp_fn, filename);

		this.dirty = false;
	};

	Wallet.prototype.setNetwork = function(netname) {
		if (!netname)
			netname = this.datastore.network;

		switch (netname) {
		case "mainnet":
		case "livenet":
			this.network = networks.livenet;
			break;
		case "testnet":
			this.network = networks.testnet;
			break;
		default:
			throw new Error("Unsupported network");
		}

		// store+canonicalize name
		this.datastore['network'] = this.network.name;
		this.dirty = true;
	};

	Wallet.prototype.addKey = function(wkey) {
		this.datastore.keys.push(wkey);
		this.dirty = true;
	};

	Wallet.prototype.addSIN = function(sinObj) {
		this.datastore.sin[sinObj.sin] = sinObj;
		this.dirty = true;
	};

	Wallet.prototype.findKeyHash = function(pubKeyHash) {
		var pkhStr = pubKeyHash.toString();

		for (var i = 0; i < this.datastore.keys.length; i++) {
			var obj = this.datastore.keys[i];
			var addrStr = obj.addr;
			var addr = new Address(addrStr);
			if (addr.payload().toString() == pkhStr)
				return obj;
		}

		return undefined;
	};

	Wallet.prototype.expandKey = function(key) {
		var addr = new Address(key);
		var isAddr = true;

		try {
			addr.validate();
			var b = addr.payload();
			var obj = this.findKeyHash(b);
			key = obj.pub;
		} catch(e) {
			// do nothing
		}

		var re = /^[a-fA-F0-9]+$/;
		if (!key.match(re))
			throw new Error("Unknown key type");
		return hex(key);
	};

	Wallet.prototype.expandKeys = function(keys) {
		var res = [];
		var us = this;
		keys.forEach(function(key) {
			var expKey = us.expandKey(key);
			res.push(expKey);
		});
		return res;
	};

	Wallet.prototype.addScript = function(script) {
		var buf = script.getBuffer();
		var hash = util.sha256ripe160(buf);
		var addr = new Address(this.network.addressScript, hash);
		var addrStr = addr.as('base58');
		this.datastore.scripts[addrStr] = buf.toString('hex');
		this.dirty = true;

		return addrStr;
	};

	return Wallet;
};
module.defineClass(ClassSpec);