var specURL = 'https://api.apis.guru/v2/specs/spotify.com/v1/swagger.yaml'; // data urls are OK too 'data:application/json;base64,abc...'
var specURL = 'https://raw.githubusercontent.com/OAI/OpenAPI-Specification/master/examples/v2.0/json/petstore.json'
//var specURL = 'https://raw.githubusercontent.com/OAI/OpenAPI-Specification/master/examples/v3.0/petstore.yaml'
var specURL = 'https://petstore.swagger.io/v2/swagger.json'
//var specURL = 'https://api.apis.guru/v2/specs/fantasydata.net/nba-v3-scores/1.0/swagger.yaml'
//var specURL = 'https://api.apis.guru/v2/specs/twilio.com/2010-04-01/swagger.yaml'
//var specURL = 'https://api.apis.guru/v2/specs/spotify.com/v1/swagger.yaml'
var specURL = 'http://206.189.169.115/testfiles/spotify.yaml'
//var specURL = 'http://206.189.169.115/testfiles/jira.yaml'
//var specURL = 'http://206.189.169.115/testfiles/jira2.json'
//SwaggerClient.http.withCredentials = true; // this activates CORS, if necessary

var apiKey = '0bbeb12ee2204fb9b864844577453a02'
var data = {"stepCounter":0, 'stepContexts':[], "specs":[]}

function getHash(str) {
	return CryptoJS.SHA256("asdf").toString()
}

function getVars(fnStr) {
	function _getvars(body) {
		if (!body) {
			return;
		}
		if (body.length) {
			for (var i = 0; i < body.length; i++) {
				_getvars(body[i]);
			}
		} else if ("VariableDeclaration" === body.type) {
			for (var i = 0; i < body.declarations.length; i++) {
				vars.push(body.declarations[i].id.name);
			}
		} else if (body.body) {
			_getvars(body.body);
		} 		
	}
	var vars = [];
	var syntax = esprima.parse(fnStr);
	_getvars(syntax.body);
	//document.getElementById("ast").innerHTML = JSON.stringify(syntax, null, 4);
	return vars;
}

function syntaxHighlight(json) {
    json = json.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
    return json.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g, function (match) {
        var cls = 'number';
        if (/^"/.test(match)) {
            if (/:$/.test(match)) {
                cls = 'key';
            } else {
                cls = 'string';
            }
        } else if (/true|false/.test(match)) {
            cls = 'boolean';
        } else if (/null/.test(match)) {
            cls = 'null';
        }
        return '<span class="' + cls + '">' + match + '</span>';
    });
}


function jq( myid ) {
 
    return myid.replace( /(:|\.|\[|\]|,|=|@)/g, "\\\\$1" );
 
}
function escapeSelector(s){
    return s.replace( /(:|\.|\[|\])/g, "\\\\$1" );
}
function somefunction(selector) {
    return selector.replace(/(!|"|#|\$|%|\'|\(|\)|\*|\+|\,|\.|\/|\:|\;|\?|@|{|})/g, function($1, $2) {
        return "\\" + $2;
    });
}

function getTypeFromRef(ref) {
	return ref.substr(ref.lastIndexOf('/') + 1)
}

function generateHTMLForSchemaStartInputs(paramID, param, definitions) {
	var schema = param['schema']

	
	inputID = thisOperationID + "-input-" + paramID 
	outputHTML = $.parseHTML(`<div class="param-name" id="${paramID}"-name">name: ${param['name']}</div>
	<div class="param-required" id="${paramID}-required">required:${param['required']}</div>
	<div class="param-description" id="${paramID}-description">description${param['description']}</div>
	`)
	$(outputHTML).append(generateHTMLForSchema(param, definitions))
	return outputHTML
}
function generateHTMLForSchema(schema, specURL) {
	//1. null schema 
	//2. ref
	//t
	//2. type['array']
	//3. type['array'] with type['object'] inside 
	var definitions = data['specs'][specURL]['swagger']['apiDefinition']['definitionFullyResolved']['definitions']
	//console.log("generating schema", schema)
	if (schema == null) {
		return $.parseHTML(`<div>Empty</div>`)
	}
	if (schema.hasOwnProperty('$ref')) {
		//console.log('got ref', schema['$ref'])
		var typeFromRef = getTypeFromRef(schema['$ref'])
		var def = definitions[typeFromRef]
		//console.log("checking def", def)
		//console.log("definitions", definitions)
		//console.log("calling in for ref", schema, def)
		defHTML = generateHTMLForSchema(def, specURL)
		$(defHTML).addClass("ref-object-value")
		
		
		return $($.parseHTML(`<div class="ref-text">${typeFromRef}</div>`)).append(defHTML)
		//return $.parseHTML(`<div class="object-value">${getTypeFromRef(schema['$ref'])}</div>`)
	}
	else if (schema['type'] == "string") {
		return $.parseHTML(`<div class="object-value-type">string</div>`)
	}
	else if (schema['type'] == "integer") {
		return $.parseHTML(`<div class="object-value-type">integer</div>`)
	}
	//handle type in schema 
	var objectHTML = ""
	//var root = $.parseHTML(`<div class="schemaType">${schema['type']}</div>`)
	if (schema['type'] == 'array') {
		objectHTML = $("<div></div>", {id: "array"})
		$(objectHTML).append("[")
		$(objectHTML).append(generateHTMLForSchema(schema['items'], specURL))
		$(objectHTML).append("]")
	}
	else if (schema['type'] == 'object') {
		//console.log("recursively callign ",schema['properties'])
		objectHTML = $(`<div id="object" ></div>`, {id : "object"})
		objectHTML.append($.parseHTML(`{`))
		for (var p in schema['properties']) {
			var pHTML = $.parseHTML(`<div class="object-key ${p}-object-key">"${p}"</div>
					<div class="object value ${p}-object-value"></div>`)
			//console.log("calling in for schema ", p, schema['properties'][p],schema)
			//print_call_stack()
			//console.log("filter", $(pHTML).filter(`.${p}-object-value`))
			$(pHTML).filter(`.${p}-object-value`).append(
					generateHTMLForSchema(schema['properties'][p], specURL))
			//console.log('properties', objectHTML)
			objectHTML.append(pHTML)
		}
		objectHTML.append($.parseHTML(`}`))
		//console.log("got objectHTML" , objectHTML)
	}
	return objectHTML 
}


function getProxyURL(url) {
	return "/proxy/" + url
}

function getURLForOperation(specURL, operationIndex) {
	thisOperation = data['specs'][specURL]['operations'][operationIndex]
	apiDefinition =  data['specs'][specURL]['swagger']['apiDefinition']
	var schemes = apiDefinition['schemes']
	var useHTTPS = false
	for (var s in schemes) {
		if  (schemes[s] == "https"){
			useHTTPS = true
		}
	}
	console.log("use HTTPS?", useHTTPS)
	return getProxyURL("http" + (useHTTPS ? "s" : "") + "\://" +  apiDefinition['host'] + "/" + 
		apiDefinition['basePath'] + "/" + thisOperation['pathObject']['path'])
}

function getValueFromContext(ctxt, code) {
	if (code == "" ) {
		console.log("returning false", code)
		return false
	}
	var variables = Object.keys(ctxt)
	var values = Object.values(ctxt)
	var fConstructArgs = variables
	fConstructArgs.push("return " + code)
	var f = new Function(...fConstructArgs)
	var ret = f.apply(null,values)
	if (!ret)
		ret = {}
	console.log("got ret from context", ret)
	return ret
}
function prepAjaxWithInput(ctxt, stepIndex, reqBlob, operationDefinition, inputIndex, parameterValue) {
	parameterValue.trim()
	var thisInput = operationDefinition["parameters"][inputIndex]
	var inputName = thisInput['name']

	var queryParams = {}
	var isRawValue = parameterValue.startsWith('"') && parameterValue.endsWith('"')
	var valueToUse = ""
	if (isRawValue){
		valueToUse = parameterValue.slice(1, -1)
	}
	else {
		valueToUse = getValueFromContext(ctxt, parameterValue)
	}
	console.log("got value", parameterValue,valueToUse)
	if (valueToUse) {
		if (thisInput["in"] == 'path'){
			console.log("in path before" , reqBlob['url'])
			reqBlob['url'] = reqBlob['url'].replace("{" + inputName+ "}", encodeURI(valueToUse) )
			console.log("in path after" , reqBlob['url'])
		}
		if (thisInput["in"] == 'query') {
			queryParams[thisInput["name"]] = valueToUse
			console.log("input name " , inputName)
			reqBlob["url"] = reqBlob["url"] + inputName + "=" + valueToUse + "&"
		}
		if (thisInput["in"] == 'body') {
			queryParams[thisInput["name"]] = parameterValue
			console.log("input name " , inputName)
			console.log("input name " , inputName)
			reqBlob["data"] = JSON.stringify(valueToUse)
			
		}
	}
	return reqBlob
}
	/*
	if (!parameterValue) {
		valueToUse[

	}
*/
	
	//reqBlob["url"] = reqBlob["url"] + "?" + $.param(queryParams)
	

var childWindow; 
function handleOAuthSuccess(result) {
	console.log("result ", result["access_token"])
	$(`[name="api-key"]`).val(result["access_token"])
	
}
function finishedOAuth(code) {
	console.log("code", code)
	childWindow.close()
	$.ajax({
		type: "POST",
		url: getProxyURL("https://accounts.spotify.com/api/token"),
		data: {"code": code, 
			"grant_type": "authorization_code",
			"client_id":"ed21b711739b4667a829b7c7e5f577cb" ,
			"client_secret":"9f92deca6c5a42d38dc972388dc7fc45" ,
			"redirect_uri" : encodeURI( "http://206.189.169.115/oauth/")},
	httpsOptions:{},
		success: handleOAuthSuccess,
	});

}

function oauth() {
	scopes = ["playlist-modify-private",
		"playlist-modify-public" ,
		"playlist-read-collaborative",
		"playlist-read-private",
		"user-follow-modify",
		"user-follow-read",
		"user-library-modify",
		"user-library-read",
		"user-read-birthdate",
		"user-read-email",		
		"user-modify-playback-state",
		"user-read-currently-playing",
		"user-read-private"]

	scopesStr = scopes.join(" ")
	console.log(scopesStr)
	url = 
		`https://accounts.spotify.com/authorize?client_id=ed21b711739b4667a829b7c7e5f577cb&response_type=code&state=5ca75bd29&redirect_uri=http://206.189.169.115/oauth/&scope=${scopesStr}`
	childWindow = window.open(url,'authWindow', 'width=800, height=600');
}

function prepAjaxWithSecurity(reqBlob, specURL) {
	var apiKey = $(`[name="api-key"]`).val()
	//reqBlob['headers']["Ocp-Apim-Subscription-Key"] = apiKey
	var apiSecurity = data['specs'][specURL]['swagger']['apiDefinition']['securityDefinitions']
	console.log("apiSecurity", apiSecurity)
	for (var key in apiSecurity) {
		var scheme = apiSecurity[key]
		console.log("scheme ", scheme)
		if (scheme['type'] == "basic")  {
			reqBlob['headers']["Authorization"] = `Basic ${apiKey}`
		}
		else if (scheme['type'] == "oauth2" && 
			scheme['flow'] == 'accessCode') {
			reqBlob['headers']["Authorization"] = `Bearer ${apiKey}`
			break;
		}
		else if (scheme['type'] == "apiKey") {
			if (scheme['in'] == 'header')
			{
				reqBlob['headers'][scheme['name']] = apiKey
				break
			}
			else if (scheme['in'] == 'query') {
				//todoc:
			}
		}
	}
	return reqBlob
}

function displayInTypeInspector(specURL,operationDefinition) {
	$( ".tabs" ).tabs( "option", "active",  0);

	$("#StepInspector").empty()
	var spec= {}
	spec['paths'] = [operationDefinition]
	SwaggerUIBundle({'url':specURL, "dom_id":'#Steps'})

}

function displayInExecutionWindow(variableName, content) {
	$( ".tabs" ).tabs( "option", "active", 1 );

	$("#Console").empty()
	//$("#executionWindow").append(`<pre id="json">${syntaxHighlight(JSON.stringify(content, null, 2))}</pre>`)
/*
	console.log(typeof content)
	$("#Console").append(`<pre id="json">${syntaxHighlight(JSON.stringify(content, null, 4))}</pre>`)
		return
*/
	console.log("type of content", typeof content)
	if (typeof content != 'object' && typeof content != 'array') {
		$("#Console").append(`${JSON.stringify(content, null, 4)}`)		
	}
	else {
	$("#Console").append(`<h1 class="executionWindowVariableName">${variableName}</h1><div class="jsonTree"</div>`)
	var tree = jsonTree.create(content, $(".jsonTree")[0]);
	tree.expand()
	return
	tree.expand(function(node) {
			return true
			//return node.childNodes.length < 2 ;
});
	}

}

function deleteStep(stepSelector, specURL, operationIndex) {
	console.log("deleting step", stepSelector)
	$(stepSelector).remove()
}

function runStep(stepSelector, specURL, operationIndex) {
	var operationDefinition = data['specs'][specURL]['operations'][operationIndex]
	console.log(operationDefinition)
	var urlForOperation = getURLForOperation(specURL, operationIndex) + "?"
	console.log("running step " + stepSelector, specURL, operationIndex, urlForOperation)
	var thisStep = $(stepSelector)
	var stepIndex = $(thisStep).data("stepindex")
	inputDivs = $(thisStep).find(".operation-input")
	outputDivs = $(thisStep).find(".operation-output")
	console.log("inputDivs", inputDivs)
	console.log("outputDivs", outputDivs)

	var ctxt = gatherContextForStep(stepIndex)

	//console.log("outputDivs", outputputDivs)
	function handleSuccessStep(result) {
		$("#executionWindow").empty()
		//save outputs
		var outputVariableName
		$(outputDivs).each( function (index, thisOutput) {
			console.log("this output", thisOutput)
			outputVariableName = $($(thisOutput).filter(".operation-output-textbox")[0]).val() //should'nt this be find ?TODO
			console.log("got output param",outputVariableName)
			if (outputVariableName) {
				data['stepContexts'][stepIndex]["outputs"][outputVariableName] = ret["responseJSON"]
				displayInExecutionWindow(outputVariableName, ret["responseJSON"])
			}
			//save json output
		})

	}
	function handleFailureStep(result) {

	}


	var reqBlob = {
		'headers':{},
		url: urlForOperation,
		success: handleSuccessStep, 
		error: handleFailureStep,
		error: handleFailureStep,
		contentType:"application/json",
		method: operationDefinition['method']
	}
	reqBlob['headers']['x-requested-with'] = 'foo'

	$(inputDivs).each( function (index, thisInput) {
		var inputIndex = $(thisInput).attr("data-inputIndex")
		console.assert(inputIndex == index)
		var inputValue = $(thisInput).find(".operation-input-textbox").val()
		console.log("got param",inputValue)
		reqBlob = prepAjaxWithInput(ctxt, stepIndex, reqBlob, data['specs'][specURL]['operations'][operationIndex], inputIndex, inputValue)
	})

	//console.log(thisStep)
	reqBlob = prepAjaxWithSecurity(reqBlob, specURL)
	
	var ret = $.ajax(
		reqBlob
		)
	
}

function initStepContext(specURL, operationIndex) {
	console.assert(data['stepCounter'] >= operationIndex, operationIndex)
	data['stepContexts'][operationIndex] =
	{
		outputs:{}
	}
}

function createStep(specURL, operationIndex) {
	var stepCounter = data['stepCounter']
	data['stepCounter']++
	initStepContext(specURL, stepCounter)
	thisStepID = `step-${stepCounter}-${thisOperationID}`
	thisOperation = data['specs'][specURL]['operations'][operationIndex]
	thisOperationPath = thisOperation['pathObject']['path']
	thisOperationMethod = thisOperation['method']

	var objectHTML = $.parseHTML(`<div data-steptype="httpstep" data-stepindex=${stepCounter} class="step ${thisStepID}" ></div>`)

	$(objectHTML).append(createOperation(specURL, operationIndex))
	$(objectHTML).filter(".step").data("operation", thisOperation)

	thisOperationID = `${thisOperationMethod.toUpperCase()}-${thisOperationPath}`
	$(objectHTML).accordion({
		collapsible: true,
		header:".sidebar-header",
		heightStyle:"content"
		}
		)
	//edit as a step 
	$(objectHTML).find(".openInInspector").remove()
	$(objectHTML).find(".create-step").remove()
	$(objectHTML).find(".operation-second-line").each(function(i) {
		//console.log(i)
		$(this).append('<input class="operation-input-textbox"></input>')
	})
	$(objectHTML).find(".operation-outputs").append('<div class="operation-output-textbox">$<input placeholder="variable-name" class="operation-output operation-output-textbox"></input></div>')
	$(objectHTML).find(".sidebar-header").append(getStepHeaderButtons(specURL, thisStepID, operationIndex))
	$(objectHTML).find(".run-step").click(function(e) {
		e.stopPropagation(e)
		var stepSelector = $(this).attr('data-stepSelector')
		var specURL = $(this).attr('data-specURL')
		var operationIndex = $(this).attr('data-operationIndex')
		runStep(stepSelector, specURL, operationIndex)
	})
	$(objectHTML).find(".delete-step").click(function(e) {
		e.stopPropagation(e)
		var stepSelector = $(this).attr('data-stepSelector')
		var specURL = $(this).attr('data-specURL')
		var operationIndex = $(this).attr('data-operationIndex')
		deleteStep(stepSelector, specURL, operationIndex)
	})
		
	
	//console.log(objectHTML)
	return objectHTML
}

var serializers = {}

function serializeProcessStep(step) {
	var stepCounter = $(step).data("steptype")
	var editor = $($(step).find(".editor")[0]).data("editor")
	var code = editor.getValue()
	return {
		"code": code
	}
}

function serializeHttpStep(step) {
	var inputDivs = $(thisStep).find(".operation-input")
	var outputDivs= $(thisStep).find(".operation-output")
	var thisOperation = $(thisStep).data("operation")
	console.log("inputDivs", inputDivs)
	console.log("outputDivs", outputDivs)
	var result = {
		"inputs": {},
		"output": "",
		"operation" : thisOperation
	}

	$(inputDivs).each( function (index, thisInput) {
		var paramName = $($(thisInput).find("div.param-name")[0]).data("param-name")
		var inputIndex = $(thisInput).attr("data-inputIndex")
		console.assert(inputIndex == index)
		var inputValue = $(thisInput).find(".operation-input-textbox").val()
		console.log("got param",paramName, inputValue)
		result['inputs'][paramName] = inputValue
	})
	
	$(outputDivs).each( function (index, thisOutput) {
		console.log("this output", thisOutput)
		var outputVariableName = $($(thisOutput).filter(".operation-output-textbox")[0]).val() //should'nt this be find ?TODO
		console.log("got output param",outputVariableName)
		result['output'] = outputVariableName
	})
	return result
}

function getStringAtURL(link, completeFunc) {
	return new Promise( function (resolve, reject) {
	$.ajax({
		url: link,
		type: 'get',
		success: function( data, textStatus, jQxhr ){
			resolve(data)
			
		},
		error: function( jqXhr, textStatus, errorThrown ){
			reject( errorThrown );
		}
	})
	})
}

//TODO TEST 
function saveSpecs() {
	var p = []
	for (var s in data['specs']) {
		var spec = data['specs'][s]['swagger']
		var hash = spec['hash']
		p.push($.ajax({
			url: `task?hash=${hash}`,
			method :'post',
			data: spec['fileContents']
		}))
	}
	return Promise.all(p)
}

function saveAll(taskname) {
	var taskBlob = serializeTask()
	return saveTask(taskname, taskBlob)
}

function saveTask(taskName, taskBlob) {
	return $.ajax({
		url: `task?taskName=${taskName}`,
		dataType: 'json',
		type: 'post',
		contentType: 'application/json',
		data: taskBlob,
		//processData: false,
		});
}

function serializeTask() {
	var allSteps = $("#mainWindow .step")
	var result = {"swaggers":{},"steps": []}
	
	for (var specURL in data['specs']){
		result['swaggers'][specURL] = data['swaggers']
	}
	
	for (var i = 0 ; i < allSteps.length; i++) {
		thisStep = allSteps[i]
		var stepType = $(thisStep).data("steptype")
		var serializeFunc = serializers[stepType]
		console.log(serializers)
		console.log(serializeFunc)
		var serialized = serializeFunc(thisStep)
		result["steps"].push(serialized)
	}
	return result
}

function gatherContextForStep(operationIndex){
	var ctxt = {}
	for (var i = 0 ; i < data['stepContexts'].length; i++) {
		var vars = data['stepContexts'][i]['outputs']
		for (var name in vars) {
			ctxt[name] = vars[name]
		}
	}
	return ctxt
}

function runProcessStep(stepSelector, specURL) {
	var thisStep = $(stepSelector)
	var stepIndex = $(thisStep).data("stepindex")
	var editor = $($(thisStep).find(".editor")[0]).data("editor")
	//outputDivs = $(thisStep).find(".operation-outputs")
	var code = editor.getValue()
	console.log(code)
	var ctxt = gatherContextForStep(stepIndex )
	var fConstructArgs = []
	
	variables = Object.keys(ctxt)
	values = Object.values(ctxt)
	console.log("got variables" , variables , values)

	fConstructArgs = variables
	/*console.log("fConstructArgs" , fConstructArgs)
	console.log("values" , values)
	console.log("values" , ...fConstructArgs)*/
	var vars = getVars(code)
	vars.forEach(function (element, index) {
		vars[index] = `"${element}"`

	})
	var varsArrayString = `[${vars.join(',')}]`
	var gatherVarsCode =
`

	var variableValues = {}
	var variablesToCapture = ${varsArrayString}
	if (variablesToCapture.length){
		variablesToCapture.forEach(function(___var) {
			var ___value = eval(___var);
			variableValues[___var] = ___value
	})
	}
	return variableValues
`
	console.log(gatherVarsCode)
	fConstructArgs.push(code  + gatherVarsCode)
	var f = new Function(...fConstructArgs)
	var ret = f.apply(null,values)
	
	console.log("code", fConstructArgs[-1])
	console.log("ret", ret)
	
	if (!ret)
		ret = {}
	displayInExecutionWindow("variables", ret)
	
	for (var variableName in ret) {
		data['stepContexts'][stepIndex]["outputs"][variableName] = ret[variableName]
	}
	
	return
}
function getStepHeaderButtons(specURL, thisStepID, operationIndex) {
	return `<button data-stepSelector=".${somefunction(thisStepID)}" data-specURL="${specURL}" data-operationIndex="${operationIndex}" class="delete-step" >X</button>
<button data-stepSelector=".${somefunction(thisStepID)}" data-specURL="${specURL}" data-operationIndex="${operationIndex}" class="run-step" >Run</button>
`
}

/*
function createAssertStep() {
	console.log("in create assert step")
	var stepCounter = data['stepCounter']
	data['stepCounter']++
	initStepContext(specURL, stepCounter)
	thisStepID = `step-${stepCounter}-`

	var objectHTML = $.parseHTML(`<div data-stepIndex=${stepCounter} style="; " class="${thisStepID}" id='accordion'></div>`)

	var root = $(objectHTML).filter(`.${thisStepID}`)
	root.append(
	`
	<h1 class='sidebar-header' style='width:100% float:left'>Assert step
	<div style='float:right' >
	</div>
	</h1>
	`)
	
	root.append(
	`
	<div id="editorDiv">
		<div class="editor"></div>
		<div class="operation-outputs" </div>
	</div>
`)
	//$(objectHTML).append(createOperation(specURL, operationIndex))

	//thisOperation = data[specURL]['operations'][operationIndex]
	//thisOperationPath = thisOperation['pathObject']['path']
	//thisOperationMethod = thisOperation['method']
	$(objectHTML).accordion({
		collapsible: true,
		header:".sidebar-header",
		heightStyle:"content"
		}
		)
	//edit as a step 
	$(objectHTML).find(".create-step").remove()
/*
	$(objectHTML).find(".operation-second-line").each(function(i) {
		//console.log(i)
		$(this).append('<input class="operation-input-textbox"></input>')
	})
*/
/*
	$(objectHTML).find(".operation-outputs").append('<div class="operation-output-textbox">$<input placeholder="variable-name" class="operation-output-textbox"></input></div>')
	$(objectHTML).find(".sidebar-header").append(getStepHeaderButtons(specURL, thisStepID, stepCounter))
	$(objectHTML).find(".run-step").click(function(e) {
		e.stopPropagation(e)
		var stepSelector = $(this).attr('data-stepSelector')
		var domain = $(this).attr('data-specURL')
		runProcessStep(stepSelector, domain)
	})
	$(objectHTML).find(".delete-step").click(function(e) {
		e.stopPropagation(e)
		var stepSelector = $(this).attr('data-stepSelector')
		var domain = $(this).attr('data-specURL')
		var operationIndex = $(this).attr('data-operationIndex')
		deleteStep(stepSelector, domain, operationIndex)
	})
		
	return objectHTML
}
*/

function createProcessStep() {
	console.log("in create process step")
	var stepCounter = data['stepCounter']
	data['stepCounter']++
	initStepContext(specURL, stepCounter)
	thisStepID = `step-${stepCounter}-`

	var objectHTML = $.parseHTML(`<div data-steptype="processStep" data-stepIndex=${stepCounter} style="; " class="step ${thisStepID}" ></div>`)

	var root = $(objectHTML).filter(`.${thisStepID}`)
	root.append(
	`
	<h1 class='sidebar-header' style='width:100% float:left'>Process step
	<div style='float:right' >
	</div>
	</h1>
	`)
	
	root.append(
	`
	<div id="editorDiv">
		<div class="editor"></div>
		<div class="operation-outputs" </div>
	</div>
`)
	//$(objectHTML).append(createOperation(specURL, operationIndex))

	//thisOperation = data[specURL]['operations'][operationIndex]
	//thisOperationPath = thisOperation['pathObject']['path']
	//thisOperationMethod = thisOperation['method']
	$(objectHTML).accordion({
		collapsible: true,
		header:".sidebar-header",
		heightStyle:"content"
		}
		)
	//edit as a step 
	$(objectHTML).find(".create-step").remove()
/*
	$(objectHTML).find(".operation-second-line").each(function(i) {
		//console.log(i)
		$(this).append('<input class="operation-input-textbox"></input>')
	})
*/
	//$(objectHTML).find(".operation-outputs").append('<div class="operation-output-textbox">$<input placeholder="variable-name" class="operation-output-textbox"></input></div>')
	$(objectHTML).find(".sidebar-header").append(getStepHeaderButtons(specURL, thisStepID, stepCounter))
	$(objectHTML).find(".run-step").click(function(e) {
		e.stopPropagation(e)
		var stepSelector = $(this).attr('data-stepSelector')
		var specURL = $(this).attr('data-specURL')
		runProcessStep(stepSelector, specURL)
	})
	$(objectHTML).find(".delete-step").click(function(e) {
		e.stopPropagation(e)
		var stepSelector = $(this).attr('data-stepSelector')
		var specURL= $(this).attr('data-specURL')
		var operationIndex = $(this).attr('data-operationIndex')
		deleteStep(stepSelector, specURL, operationIndex)
	})
		
	return objectHTML
}

/*
function createAssertOperation() {
	thisOperationID = "AssertStep"
	opHTML = $.parseHTML(
		`<div style='width:100%' id="${thisOperationID}"/>`)
	//get summary
	summary = 'Assert Step allows you to assert a condition'
	descriptionDiv = `<div id="${thisOperationID}-summary" >${summary}</div>`

	//add to html	
	$(opHTML).filter("#" + somefunction(thisOperationID)).append(
	`
	<h1 class='sidebar-header' style='width:100% float:left'>${thisOperationID}
	<div style='float:right' >
	<button class="create-assert-step">Create Step</button></div>
	</h1>
	<div id="${thisOperationID}-body" >
	${descriptionDiv}
	<div id="${thisOperationID}-params">
	<div class='operation-inputs'></div>
	<br>
	<br>
	<br>
	<div class='operation-outputs'>
	</div>
	</div>
	</div>
	`)
	
	console.log("assert step", opHTML)
	console.log("assert step", $(opHTML).filter("#" + somefunction(thisOperationID)))
	return opHTML
}
*/

function createProcessOperation() {
	thisOperationID = "ProcessStep"
	opHTML = $.parseHTML(
		`<div style='width:100%' id="${thisOperationID}"/>`)
	//get summary
	summary = 'Process Step allows you to write code to modify data'
	descriptionDiv = `<div id="${thisOperationID}-summary" >${summary}</div>`

	//add to html	
	$(opHTML).filter("#" + somefunction(thisOperationID)).append(
	`
	<h1 class='sidebar-header' style='width:100% float:left'>${thisOperationID}
	<div style='float:right' >
	<button class="create-process-step">Create Step</button></div>
	</h1>
	<div id="${thisOperationID}-body" >
	${descriptionDiv}
	<div id="${thisOperationID}-params">
	<div class='operation-inputs'></div>
	<br>
	<br>
	<br>
	<div class='operation-outputs'>
	</div>
	</div>
	</div>
	`)
	
	///console.log("got outputs", outputs)
	//$('<div>').append(opHTML).find(`.operation-inputs`).append(inputsDiv)
	//$('<div>').append(opHTML).find(`.operation-outputs`).append(outputs)
	console.log("process step", opHTML)
	console.log("process step", $(opHTML).filter("#" + somefunction(thisOperationID)))
	return opHTML

}

function createOperation(specURL, operationIndex) {
	thisOperation = data['specs'][specURL]['operations'][operationIndex]
	//console.log("thisOperation", thisOperation)
	thisOperationPath = thisOperation['pathObject']['path']
	thisOperationMethod = thisOperation['method']
	thisOperationID = `${thisOperationMethod.toUpperCase()}-${thisOperationPath}`
	opHTML = $.parseHTML(
		`<div style='width:100%' data-operationIndex='${operationIndex}' id="${thisOperationID}"/>`)
	//get input parameters
	inputs = thisOperation['definition']['parameters']
	inputsDiv =  $.parseHTML(`<div id='${thisOperationID}-inputs'><h3>INPUTS</h3></div>`)
	for (var input in inputs) {
		thisParam = inputs[input]
		inputID = thisOperationID+ "-input-" + input
		//generate inputs type 
		//if [inputs['type']
		var paramText = thisParam['name'] + "<span class='param-required-span'>" + (thisParam['required'] ? " (required)" :  "") + "</span>"
		$(inputsDiv).append( 
		$.parseHTML(`<div class='operation-input' data-inputIndex="${input}" data-inputID="${inputID}" id="${inputID}">
			<div data-param-name="${thisParam['name']}" class="param-name" id="${inputID}-name">name: ${paramText}</div>
			<div class="param-type" id="${inputID}-type">type: 
				</div>
			<div class='operation-second-line'>
			<div class="param-description" id="${inputID}-description">${thisParam['description']}</div>
			</div>
		 </div><br><br>`))
		var objectWithTypeField = 'schema' in thisParam? thisParam['schema']: thisParam
		var input = generateHTMLForSchema(objectWithTypeField, specURL)
		$(input).addClass('input-type-value')
		$(inputsDiv).find(`#${somefunction(inputID)}-type`).append(input)

	}

	var responseInfo  = thisOperation['definition']['responses']
	//console.log(responseInfo)
	var outputs=""
	if (!(200 in responseInfo) || !('schema' in responseInfo[200])) {
		outputs = ""
	}
	else {
		//console.log("Definitions", data[specURL]['swagger']["definitions"])
		outputs = generateHTMLForSchema(responseInfo[200]['schema'], specURL)
	}
	outputsDiv =  ""
	
	outputsDiv += `<div class="operation-outputs" id='${thisOperationID}-outputs'><h3>OUTPUTS</h3></div>`

	//get summary
	summary = thisOperation['summary'] ? thisOperation['summary'] : thisOperation['description']
	descriptionDiv = `<div id="${thisOperationID}-summary" >${summary}</div>`

	//add to html	
	$(opHTML).filter("#" + somefunction(thisOperationID)).append(
	`
	<h1 class='sidebar-header' style='width:100% float:left'>${thisOperationID}
	<div style='float:right' ><button data-specURL='${specURL}' data-operationIndex='${operationIndex}' class="create-step">Create Step</button></div>
	</h1>
	<div id="${thisOperationID}-body" >
	${descriptionDiv}
	<div id="${thisOperationID}-params">
	<div class='operation-inputs'></div>
	<br>
	<br>
	<br>
	${outputsDiv}
	</div>
	<a class="openInInspector">Open in Inspector</a>
	</div>
	`)
	//console.log("got outputs", outputs)
	$('<div>').append(opHTML).find(`.operation-inputs`).append(inputsDiv)
	$('<div>').append(opHTML).find(`.operation-outputs`).append(outputs)
	$(opHTML).find(".openInInspector").click(function (e) {
		e.stopPropagation()
		displayInTypeInspector(specURL, thisOperation)
	})
	return opHTML
}

function createEditorOptions(source) {
	return {
		'value': source,
		'language': 'javascript',
		  'codeLens': false,
		  'theme': "vs-dark",
		  'automaticLayout': true
	}

}
var s = Sway.create({
	definition: specURL
	}).then(function (apiDefinition) {
	data['specs'][specURL] = {
		'swagger':{},
		'operations': [],
		'operationCounter': 0,
		'contexts': []
	}
	data['specs'][specURL]['swagger'] = {"apiDefinition": apiDefinition,
		"hash":getHash(""),
		"fileContents": "",
		"url":specURL,
		"filename":specURL
	}
	console.log(apiDefinition)
	var operations = apiDefinition.getOperations()
	console.log(operations)

	//var assertStepHTML = createAssertOperation()
	var processStepHTML = createProcessOperation()

	$('#sidebar').append(processStepHTML)
	//$('#sidebar').append(assertStepHTML)

	for (var op in operations) {
		if (operations.hasOwnProperty(op)) {
			thisOperation = operations[op]
			//thisOperation = data[specURL]['operations'][thisOperationID]
			thisOperationPath = thisOperation['pathObject']['path']
			thisOperationMethod = thisOperation['method']
			thisOperationID = data['specs'][specURL]['operationCounter']++
			data['specs'][specURL]['operations'][thisOperationID] = thisOperation
			var opHTML = createOperation(specURL, thisOperationID)
			$('#sidebar').append(opHTML)
		}
	}
	//initialize UI 
	$(".tabs").tabs()
	$( "#mainWindow" ).sortable({
      placeholder: "ui-state-highlight"

	    });
	$( "#mainWindow" ).disableSelection()
	$( "#sidebar" ).accordion({
	      collapsible: true,
		header:".sidebar-header",
		heightStyle:"content"
	    });
	$(".create-step").click(function (e) {
		e.stopPropagation()
		var dataSpecURL= $(this).attr('data-specURL')
		var dataOperationIndex = $(this).attr('data-operationIndex')
		$("#mainWindow").append(createStep(specURL, dataOperationIndex))
	})
	/*
	$(".create-assert-step").click(function (e) {
		e.stopPropagation()
		var assertStep = createAssertStep(specURL)
		var stepIndex = $(assertStep).data("stepindex")
		$("#mainWindow").append(assertStep)
		var addedStep = $.find(`[data-stepindex=${stepIndex}] .editor`)[0]
		var editor = monaco.editor.create(addedStep,
			createEditorOptions(
				[
				//'assert(condition, "string to display on failure")',
				].join('\n')
			)
		)
		
		$(addedStep).data("editor",editor)
	
	})
	*/

	$(".create-process-step").click(function (e) {
		e.stopPropagation()
		var processStep = createProcessStep()
		console.log("process Step", processStep)
		var stepIndex = $(processStep).data("stepindex")
		$("#mainWindow").append(processStep)
		var addedStep = $.find(`[data-stepindex=${stepIndex}] .editor`)[0]
		console.log("got back ref", addedStep)
		var editor = monaco.editor.create(addedStep,
				createEditorOptions(
					['function x() {',
					'\tconsole.log("Hello world!");',
					'}'
					].join('\n')));

		$(addedStep).data("editor",editor)
	})
	
	//initializeSerialiers
	serializers["httpstep"] = serializeHttpStep 
	serializers["processStep"] = serializeProcessStep

	oauth()

    require.config({ paths: { 'vs': 'javascripts/monaco/min/vs' }});
    require(['vs/editor/editor.main'], function() {
    });


	}
, function (err) {
  console.error(err.stack);
});


