import util from 'util';

export default function *() {

	this.on('action.WorkBoard.connectModule', function *(moduleId, pin) {
		this.dispatch('store.Blockly.updateAvailModule', moduleId, pin);
		this.dispatch('store.WorkBoard.connectModule', moduleId, pin);
	});

	this.on('action.WorkBoard.disconnectModule', function *(moduleId, pin) {
		this.dispatch('store.Blockly.updateAvailModule', null, pin);
		this.dispatch('store.WorkBoard.disconnectModule', moduleId, pin);
	});

	this.on('action.WorkBoard.updateResults', function *(lines) {

		var results = {};

		lines.forEach(function(line) {
			var parts = line.split(':');
			var header = parts[0].split('_') || null;
			var pin = header[0];
			var name = header[1];
			var value = parts[1] || null;

			var result = results[pin] = {};
			result[name] = value;
		});

		this.dispatch('store.WorkBoard.updateResults', results);
	});

	this.on('action.WorkBoard.generateTestCode', function *() {

		var store = this.getState('WorkBoard');

		var codeStruct = {
			headers: [],
			inits: [],
			definitions: [],
			codeLines: []
		};

		function setupHeaders(headers) {
			for (var index in headers) {
				var header = headers[index];

				if (codeStruct.headers.indexOf(header) != -1)
					continue;

				codeStruct.headers.push('#include <' + header + '>');
			}
		}

		function setupInits(pin, module) {

			if (!module.init) {
				if (module.input) {
					codeStruct.inits.push('pinMode(' + store.pinTable[pin] + ', INPUT);');
				} else if (module.output) {
					codeStruct.inits.push('pinMode(' + store.pinTable[pin] + ', OUTPUT);');
				}

				return;
			}

			var code = module.init(store.pinTable[pin]);

			codeStruct.inits.push(code);
		}

		function setupDefinitions(pin, definitions) {
			for (var index in definitions) {
				var definition = definitions[index];

				// Need to substitue something
				if (definition.indexOf('%s') != -1) {
					definition = util.format(definition, store.pinTable[pin]);
				}

				if (codeStruct.definitions.indexOf(definition) != -1)
					continue;

				codeStruct.definitions.push(definition);
			}
		}

		function setupCode(pin, module) {
			var tests = module.tests || [];

			// It can be read from module via standard method
			if (module.input && !module.tests) {

				if (module.group.indexOf('digital') > -1 && module.group.indexOf('pwm') == -1) {
					// Digital
					tests.push({
						'name': 'Digital',
						'output': true, 
						'codeGen': function(pin) {
							return 'digitalRead(' + pin + ');';
						}
					});
				} else if (module.group.indexOf('digital') || store.pinDef[pin].indexOf('pwm') > -1) {
					// Analog
					tests.push({
						'name': 'Analog',
						'output': true, 
						'codeGen': function(pin) {
							return 'analogRead(' + pin + ');';
						}
					});
				}
			}

			// It will do something out
			if (module.output && !module.tests) {

				if (module.group.indexOf('digital') > -1 && module.group.indexOf('pwm') == -1) {
					// Digital
					tests.push({
						'name': 'Digital',
						'input': true, 
						'codeGen': function(pin) {
							return 'digitalWrite(' + pin + ', 1);';
						}
					});
				} else if (module.group.indexOf('digital') || store.pinDef[pin].indexOf('pwm') > -1) {
					// Analog
					tests.push({
						'name': 'Analog',
						'input': true, 
						'codeGen': function(pin) {
							return 'analogWrite(' + pin + ', 255);';
						}
					});
				}
			}

			// Customized testcases
			for (var index in tests) {
				var test = tests[index];

				// This moudle will return value 
				if (test.output) {
					var code = [
						'Serial.print(\"' + pin + '_' + test.name + ':\");',
						'Serial.println(' + test.codeGen(store.pinTable[pin]) + ');'
					];
					codeStruct.codeLines.push(code.join('\n'));
				}

				// This module is used to execute
				if (test.input) {
					codeStruct.codeLines.push(test.codeGen(store.pinTable[pin]));
				}
			}
		}

		// Generate test code for each modules
		for (var pin in store.connected) {
			var id = store.connected[pin];

			// Finding module
			for (var index in store.modules.sensors) {
				var module = store.modules.sensors[index];

				if (module.sku == id) {
					setupHeaders(module.headers || []);
					setupInits(pin, module);
					setupDefinitions(pin, module.definitions || []);
					setupCode(pin, module);
					break;
				}
			}
		}

		var code = [
			codeStruct.headers.join('\n'),
			codeStruct.definitions.join('\n'),
			'void setup() {',
			'    Serial.begin(9600);',
			codeStruct.inits.join('\n'),
			'}',
			'void loop() {',
			codeStruct.codeLines.join('\n'),
			'}'
		];

		console.log(code.join('\n'));

		var builder = this.getState('Builder');
		
		this.dispatch('store.Builder.flash', builder.selectedBoard, builder.selectedPort, code.join('\n'));
	});
};
