var mkdirp = require('mkdirp');
var path = require('path');
var fs = require('fs');
var cp = require('child_process');

var Q = require('q');
var argparse = require('argparse');
var parser = new argparse.ArgumentParser({
    addHelp: true,
    description: "Command-line utility to generate memory trace"
});
parser.addArgument(['--outputDir'], { help: "directory in which to place instrumented files and traces.  " + "We create a new sub-directory for our output.", required: true });
parser.addArgument(['--sdbPath'], { help: "The sdb path included in the installed tizen sdk" });
parser.addArgument(['--profilesName'], { help: "The Tizen application is signed with a certified profile named profiles.xml" });
parser.addArgument(['--cliPath'], { help: "The CLI is located in the $<TIZEN_SDK_HOME>/tools/ide/bin directory" });
parser.addArgument(['--serial'], { help: "Sets the serial, which installs the Tizen package" });
parser.addArgument(['inputDir'], { help: "Either a JavaScript file or an HTML app directory with an index.html file" });

var args = parser.parseArgs();
var outputDir = args.outputDir;
var buildDir=outputDir+"/.buildResult";
var sdbPath = args.sdbPath;
var profilesName = args.profilesName;
var serial = args.serial;
var cliPath = args.cliPath +"/tizen.sh";

console.log("Profiles Name : "+profilesName);
console.log("CLI Path : "+cliPath);

var projectName = getProjectName(args.inputDir);
//outputDir = 

var targetProjectFile = path.join(outputDir, '/', '.project');
var signature1File = path.join(outputDir, '/', 'signature1.xml');
var authorSignatureFile = path.join(outputDir,  '/', 'author-signature.xml');
var outputFile = path.join(outputDir, projectName + ".wgt");

//if(!fs.existsSync(targetProjectFile)){	
	//var sourceProjectFile = path.join(process.cwd(), '/tools/.project');	
	//fs.writeFileSync(targetProjectFile, fs.readFileSync(sourceProjectFile));	
//}

if(fs.existsSync(signature1File)){
	fs.unlink(signature1File);
	console.log("existed " + signature1File + " is deleted");
}
if(fs.existsSync(authorSignatureFile)){
	fs.unlink(authorSignatureFile);
	console.log("existed " + authorSignatureFile + " is deleted");
}
if(fs.existsSync(outputFile)){
	fs.unlink(outputFile);
	console.log("existed " + outputFile + " is deleted");
}
var deleteFolderRecursive = function(path) {
    var files = [];
    if( fs.existsSync(path) ) {
        files = fs.readdirSync(path);
        files.forEach(function(file,index){
            var curPath = path + "/" + file;
            if(fs.lstatSync(curPath).isDirectory()) { // recurse
                deleteFolderRecursive(curPath);
            } else { // delete file
                fs.unlinkSync(curPath);
            }
        });
        fs.rmdirSync(path);
    }
};

function buildAndInstall(sdbpath){
	var sdb=sdbpath;
	//console.log("Using sdb:"+sdb);
	//build process
	//console.log("==>Begin to spawn building process");	
	if(fs.existsSync(buildDir)){
		deleteFolderRecursive(buildDir);
		console.log("existed " + buildDir + " is removed");
	}

	var buildProc=cp.spawn(cliPath, ["build-web","--",outputDir]);
	buildProc.stdout.on('data', function(data){
		process.stdout.write(String(data));
		if(String(data).indexOf("Yes: (Y)")>=0){
			signProc.stdin.write("Y\r");
		}
	});	

	buildProc.stderr.on('data', function(data){
		process.stderr.write(String(data));
	});	
	
	buildProc.on('exit', function(code, signal){
		//console.log("exit build process with code:"+code);
		buildProc.stdout.end();
		buildProc.stderr.end();
	});
	
	buildProc.on('close', function (code) {	
		if (code !== 0) {
			console.log("building  failed");
		}
		
		
		//console.log("==>Begin to spawn signing process");
		var signProc=cp.spawn(cliPath, ['package',"--type" ,"wgt","--sign",profilesName,"--", buildDir]);
		
		signProc.stdout.on('data', function(data){
			process.stdout.write(String(data));
			if(String(data).indexOf("Yes: (Y)")>=0){
				signProc.stdin.write("Y\r");
			}
		});	

		signProc.stderr.on('data', function(data){
			process.stderr.write(String(data));
		});	
			
		signProc.on('exit', function(code, signal){
			//console.log("exit sign process with code:"+code);
			signProc.stdout.end();
			signProc.stderr.end();
		});
		
		signProc.on('close', function (code) {	
			if (code !== 0) {
				console.log("signing  failed");
			}else{
				// un-install
				//console.log("==>Begin to spawn uninstalling process");
				var uninstallProc = cp.spawn(cliPath, ['uninstall', "--serial",serial,"--pkgid",getApplicationID()]);
				uninstallProc.stdout.on('data', function (data) {
					process.stdout.write(String(data));
				});
				
				uninstallProc.stderr.on('data', function (data) {
					process.stderr.write(String(data));						
				});
				
				uninstallProc.on('exit', function(code, signal){
					//console.log("exit uninstall process with code:"+code);
					uninstallProc.stdout.end();
					uninstallProc.stderr.end();
				});
				
				uninstallProc.on('close', function (code) {
					if (code !== 0) {
						console.log("uninstall failed");
					}
					//console.log("uninstall done");
					//console.log(outputFile + " will be installed");
					//console.log("==>Begin to spawn installing process");
					var installProc = cp.spawn(cliPath, ['install',"--serial",serial, "--name",projectName + ".wgt","--",buildDir]);
					
					installProc.stdout.on('data', function (data) {
						process.stdout.write(String(data));
					});
					
					installProc.stderr.on('data', function (data) {
						process.stderr.write(String(data));							
					});
					
					installProc.on('exit', function(code, signal){
						//console.log("exit install process with code:"+code);
						installProc.stdout.end();
						installProc.stderr.end();
					});
					
					installProc.on('close', function (code){
						if(code !== 0){
							console.log(projectName + " install failed");
						} else {
							console.log(projectName + " install complete");
						}
					});
					
				});
			}			
			
			
		});
		//end add
	});	
}

function getProjectName(inputDir){	
	var config = path.join(inputDir,'/', 'config.xml');
	if(!fs.existsSync(config)){
		process.stderr.write("Tizen Configuration Error: No config.xml file.\n");
		return;
	}	
	var xml = fs.readFileSync(config);
	var parseString = require('xml2js').parseString;	

	var name;
	parseString(xml, function (err, result) {
		if(result.widget==null || typeof result.widget==="undefined"){
			process.stderr.write("Tizen Configuration Error: Make sure there is a 'widget' element in the config.xml\n");
			return;
		}
		
		var appName=result.widget['name'];		
		if(appName==null || typeof appName==="undefined"){
			process.stderr.write("Tizen Configuration Error: Make sure there is a 'tizen:application' element in the config.xml\n");
			return;
		}
		name = result.widget['name'][0];
	});
	return name;
}

function getProjectPath(inputDir,projectName){
console.log("getProjectPath....inputDir=="+inputDir);
	var len = inputDir.length;
	var pLen = projectName.length;
	
	var pathName = inputDir.substring(0,len-pLen-2);
	return pathName ;

//return inputDir;
}

//function getApplicationID(){
//var parseString = require('xml2js').parseString;
//var config = path.join(outputDir, '/', 'config.xml');
//var xml = fs.readFileSync(config);
//var id;
//parseString(xml, function (err, result) {
//	id = result.widget['tizen:application'][0].$.id;
//});
//return id;
//}

function getApplicationID(){
	var config = path.join(outputDir, '/', 'config.xml');
	if(!fs.existsSync(config)){
		process.stderr.write("Tizen Configuration Error: No config.xml file.\n");
		return;
	}	
	var xml = fs.readFileSync(config);
	var parseString = require('xml2js').parseString;	

	var packageEle;
	parseString(xml, function (err, result) {		
		if(result.widget==null || typeof result.widget==="undefined"){
			process.stderr.write("Tizen Configuration Error: Make sure there is a 'widget' element in the config.xml\n");
			return;
		}
		
		var appEle=result.widget['tizen:application'];		
		if(appEle==null || typeof appEle==="undefined"){
			process.stderr.write("Tizen Configuration Error: Make sure there is a 'tizen:application' element in the config.xml\n");
			return;
		}
		
		id = result.widget['tizen:application'][0].$.id;
		if(id==null || typeof id==="undefined"){
			process.stderr.write("Tizen Configuration Error: Make sure there is a 'id' attribute in 'tizen:application' element of the config.xml\n");
			return;
		}
		
		packageEle=appEle[0].$.package;
		if(packageEle==null || typeof packageEle==="undefined"){
			process.stderr.write("Tizen Configuration Error: Make sure there is a 'package' attribute in 'tizen:application' element of the config.xml\n");
			return;
		}		
	});
	return packageEle;
}

function withSdb(subProc, sdbInSdk, needStartServer){	
	console.log("Get available sdb...");
	var sdbInJsa='tools/sdb';
	var sdbInPath='sdb';
	
	var startSDB=function(callback, sdbPath, needStartServer){	
		console.log("SDB Path : "+sdbPath);
		if(!needStartServer) return callback(sdbPath);
		
		var sdbProc=cp.spawn(sdbPath, ['start-server']);		
		sdbProc.stdout.on('data', function (data) {
			process.stdout.write(String(data));
		});
		sdbProc.stderr.on('data', function (data) {
			process.stderr.write(String(data));
		});
		sdbProc.on('exit', function(code, signal){
			//console.log("exit sdb start-server process with code:"+code);
			//sdbProc.stdout.end();
			//sdbProc.stderr.end();
			callback(sdbPath);	
			
		});
		sdbProc.on('close', function (code) {
			console.log("Finished sdb start-server process.");	
					
		});
	}
	
	if(sdbInSdk==null || sdbInSdk=="null"){		
		try{
			var sdbCheckProc = cp.spawn(sdbInPath);
			var checked=false;
			sdbCheckProc.on('error', function(err){	
				if(!checked){	
					checked=true;	
					startSDB(subProc, sdbInJsa, needStartServer);
				}
			});
			sdbCheckProc.on('close', function (code) {		
				if(!checked){	
					checked=true;					
					startSDB(subProc, sdbInPath, needStartServer);
				}			
			});	
			
			sdbCheckProc.stdout.on('data', function (data) {
				if(!checked){	
					checked=true;
					startSDB(subProc, sdbInPath, needStartServer);
				}
			});
			sdbCheckProc.stderr.on('data', function (data) {
				if(!checked){
					checked=true;
					startSDB(subProc, sdbInPath, needStartServer);
				}
			});		
			
		}catch(e){
			if(!checked){
				checked=true;
				startSDB(subProc, sdbInJsa, needStartServer);
			}
		}
		
	}else{		
		startSDB(subProc, sdbInSdk, needStartServer);
	}	
}

withSdb(buildAndInstall, sdbPath, true);
