const {resolve} = nativeRequire("path");
var fs = nativeRequire("fs");
//const path = nativeRequire("path");
var resourceDir;

stringifyToDepth = function(data, maxDepth){
	var prettyString = ""
  var rCount = 0
  var writeArray
  var indent;

	if(maxDepth === 0) {
		JSON.stringify(data)
	} else {
		indent = function(size) {return Array.from({length: size}, () => "  ").join("")}
		writeArray = function(array) {
			prettyString = prettyString + indent(rCount) + "[\n"
			rCount = rCount + 1
			if(rCount < maxDepth) {
        array.forEach(item => writeArray(item))
			} else {
        var formmattedArray;
				formattedArray = array.map(item => indent(rCount) + JSON.stringify(item)).join(",\n")
        formattedArray = formattedArray.replaceAll("[", "[ ").replaceAll("]", " ]").replaceAll(",", ", ")
        prettyString = prettyString + formattedArray
			}
			rCount = rCount - 1;
			prettyString = prettyString + "\n" + indent(rCount) + "],\n";
		}

		writeArray(data)
    prettyString = prettyString.replaceAll(",\n\n", "\n").slice(0, -2);
    return prettyString
	}
}

loadModel = function(model){
	if(typeof model.ref_uid !== 'undefined') {receive("/ref_uid", model.ref_uid)}

	if(typeof model.order_seed !== 'undefined') {receive("/order_seed", model.order_seed)}
	if(typeof model.dur_seed !== 'undefined') {receive("/dur_seed", model.dur_seed)}
	if(typeof model.motifs_seed !== 'undefined') {receive("/weights_seed", model.motifs_seed)}

	if(typeof model.entrances_probs_vals !== 'undefined') {
		var envValsFlat = model.entrances_probs_vals.slice(5)
		var envSize = envValsFlat.length / 2
		var envVals = new Array(64).fill({type: 'f', value: 0})
		for (var i = 0; i < envSize; i++) {
			envVals[i] = [envValsFlat[i * 2], envValsFlat[i * 2 + 1]]
		}
		receive("/entrances_probs_dur_env_size", envSize)
		receive("/entrances_probs_chord_val_slider", model.entrances_probs_vals[0])
		receive("/entrances_probs_pad_val_rslider", model.entrances_probs_vals.slice(1, 3))
		receive("/entrances_probs_dur_env_rslider", ...model.entrances_probs_vals.slice(3, 5))
		receive("/entrances_probs_dur_env_canvas", ...envVals)
	}

	if(typeof model.passages_probs_vals !== 'undefined') {
		var envValsFlat = model.passages_probs_vals.slice(5)
		var envSize = envValsFlat.length / 2
		var envVals = new Array(64).fill({type: 'f', value: 0})
		for (var i = 0; i < envSize; i++) {
			envVals[i] = [envValsFlat[i * 2], envValsFlat[i * 2 + 1]]
		}
		receive("/passages_probs_dur_env_size", envSize)
		receive("/passages_probs_chord_val_slider", model.passages_probs_vals[0])
		receive("/passages_probs_pad_val_rslider", model.passages_probs_vals.slice(1, 3))
		receive("/passages_probs_dur_env_rslider", ...model.passages_probs_vals.slice(3, 5))
		receive("/passages_probs_dur_env_canvas", ...envVals)
	}

	if(typeof model.exits_probs_vals !== 'undefined') {
		var envValsFlat = model.exits_probs_vals.slice(5)
		var envSize = envValsFlat.length / 2
		var envVals = new Array(64).fill({type: 'f', value: 0})
		for (var i = 0; i < envSize; i++) {
			envVals[i] = [envValsFlat[i * 2], envValsFlat[i * 2 + 1]]
		}
		receive("/exits_probs_dur_env_size", envSize)
		receive("/exits_probs_chord_val_slider", model.exits_probs_vals[0])
		receive("/exits_probs_pad_val_rslider", model.exits_probs_vals.slice(1, 3))
		receive("/exits_probs_dur_env_rslider", ...model.exits_probs_vals.slice(3, 5))
		receive("/exits_probs_dur_env_canvas", ...envVals)
	}

	if(typeof model.ranges !== 'undefined') {
		receive("/range_matrix/0_val_rslider", ...model.ranges[0])
		receive("/range_matrix/1_val_rslider", ...model.ranges[1])
		receive("/range_matrix/2_val_rslider", ...model.ranges[2])
		receive("/range_matrix/3_val_rslider", ...model.ranges[3])
	}

	if(typeof model.passages_weights !== 'undefined') {
		receive("/passages_weights/0_val_slider", model.passages_weights[0])
		receive("/passages_weights/1_val_slider", model.passages_weights[1])
		receive("/passages_weights/2_val_slider", model.passages_weights[2])
		receive("/passages_weights/3_val_slider", model.passages_weights[3])
		receive("/passages_weights/4_val_slider", model.passages_weights[4])
	}

	if(typeof model.order !== 'undefined') {receive("/order", stringifyToDepth(model.order, 1))}

	if(typeof model.sus_weights !== 'undefined') {
		receive("/sus_weights/0_val_slider", model.sus_weights[0])
		receive("/sus_weights/1_val_slider", model.sus_weights[1])
		receive("/sus_weights/2_val_slider", model.sus_weights[2])
	}

	if(typeof model.step_probs_vals !== 'undefined') {
		var envValsFlat = model.step_probs_vals.slice(2)
		var envSize = envValsFlat.length / 2
		var envVals = new Array(64).fill({type: 'f', value: 0})
		for (var i = 0; i < envSize; i++) {
			envVals[i] = [envValsFlat[i * 2], envValsFlat[i * 2 + 1]]
		}
		receive("/step_probs_env_size", envSize)
		receive("/step_probs_env_rslider", ...model.step_probs_vals.slice(0, 2))
		receive("/step_probs_env_canvas", ...envVals)
	}

	if(typeof model.hd_exp !== 'undefined') {receive("/hd_exp_val_slider", model.hd_exp)}
	if(typeof model.hd_invert !== 'undefined') {receive("/hd_invert", model.hd_invert)}

	if(typeof model.order_size !== 'undefined') {receive("/order_size_rslider", ...model.order_size)}
	if(typeof model.passages_size !== 'undefined') {receive("/passages_size_rslider", ...model.passages_size)}

	receive("/mus_seq", stringifyToDepth(model.music_data, 3))
}

module.exports = {

    init: function(){
        // this will be executed once when the osc server starts
    },

    oscInFilter:function(data) {

      var {host, port, address, args} = data

      //console.log(data)

      if (address === '/playing') {

        var modelPath = resolve(args[0].value)
        var model = loadJSON(modelPath)
				loadModel(model)
				receive("/cur_play_index", args[1].value)
      }

      if (address === '/generated') {

        //var guiStatePath = resolve(__dirname + "/../../resources/tmp/tmp_gui_state.json")
        //var musPath = resolve(__dirname + "/../../resources/tmp/tmp_music.json")
        //var ledgerPath = resolve(__dirname + "/../../resources/piece_ledger.json")
        //var guiState = loadJSON(guiStatePath)
        //var musState = loadJSON(musPath)
        //guiState.mus_seq = musState.music_data
        //saveJSON(guiStatePath, guiState)
				var ledgerPath = args[2].value
				var model = JSON.parse(args[1].value)
        var ledger = loadJSON(ledgerPath).ledger
        ledger.push("tmp")
        var model = JSON.parse(args[1].value);
        receive("/ledger", JSON.stringify(ledger, null, '  ').replace(/['"]+/g, ''))
        receive("/mus_seq", stringifyToDepth(model.music_data, 3))
        receive("/order", stringifyToDepth(model.order, 1))
      }

      if (address === '/committed') {
          try {
            /*
            var guiStatePath = resolve(__dirname + "/../../resources/tmp/tmp_gui_state.json")
            var curUID = args[0].value
            var state = loadJSON(guiStatePath)
            state.cur_uid = curUID
            var dir = resolve(__dirname + "/../../resources/" + curUID)
            if (!fs.existsSync(dir)){
                fs.mkdirSync(dir);
            }
            guiStatePath = resolve(__dirname + "/../../resources/" + curUID + "/" + curUID + "_gui_state.json")
            saveJSON(guiStatePath, state)
            */
          } catch (e) {
              console.log(`error while committing`)
              console.error(e)
          }

          var ledgerPath = args[1].value
          receive("/ledger", JSON.stringify(loadJSON(ledgerPath).ledger, null, '  ').replace(/['"]+/g, ''))
          return
      }

      if (address === '/load_state') {
          /*
          var ref_uid = args[0].value
          loadState(loadJSON("../../resources/" + ref_uid + "/" + ref_uid + "_gui_state.json"))
          receive('/commit')
          */
          return
      }

      return data

    },

    oscOutFilter:function(data) {

        var {host, port, address, args} = data

        //console.log(data)

        if (address === '/generate') {
            try {
                var state = JSON.parse(args[0].value)

                //console.log(__dirname)
                var modelPath = resolve(resourceDir + "/tmp/tmp_mus_model.json")
                var model = {}
                model.schema_version = "1.0"
                model.cur_uid = "tmp"
                model.ref_uid = state.ref_uid
                if(model.ref_uid == "nil" || model.ref_uid == "" || model.ref_uid == "[" || model.ref_uid == "[]") {delete model["ref_uid"]}
                model.order_seed = state.order_seed
                model.dur_seed = state.dur_seed
                model.motifs_seed = state.weights_seed
                model.entrances_probs_vals = state.entrances_probs_vals
                model.passages_probs_vals = state.passages_probs_vals
                model.exits_probs_vals = state.exits_probs_vals
                model.ranges = [
                  state["range_matrix/0_val_rslider"],
                  state["range_matrix/1_val_rslider"],
                  state["range_matrix/2_val_rslider"],
                  state["range_matrix/3_val_rslider"]
                ]
                model.passages_weights = [
                  state["passages_weights/0_val_slider"],
                  state["passages_weights/1_val_slider"],
                  state["passages_weights/2_val_slider"],
                  state["passages_weights/3_val_slider"],
                  state["passages_weights/4_val_slider"]
                ]
								model.hd_exp = state.hd_exp_val_slider
								model.hd_invert = state.hd_invert
                if(state.order_lock == 1){
                  model.order = JSON.parse(state.order)
                }
                model.sus_weights = [
                  state["sus_weights/0_val_slider"],
                  state["sus_weights/1_val_slider"],
                  state["sus_weights/2_val_slider"]
                ]
                model.order_size = state.order_size_rslider
                model.passages_size = state.passages_size_rslider

								model.step_probs_vals = state.step_probs_env_vals

                model.motif_edited = false
                model.order_edited = false
                //console.log(model)
                saveJSON(modelPath, model)

                /*
                var ledgerPanelState = JSON.parse(args[1].value)
                delete ledgerPanelState.ref_uid
                var omitKeys = Object.keys(ledgerPanelState).concat(["generate", "commit"])
                //console.log(omitKeys[0])
                for(k in omitKeys) {
                  //console.log(omitKeys[k])
                  delete state[omitKeys[k]]
                }
                var guiStatePath = resolve(__dirname + "/../../resources/tmp/tmp_gui_state.json.json")
                saveJSON(guiStatePath, state)
                */

                args = args.slice(0, 1)
                args[0].value = modelPath
                return {host, port, address, args}
            } catch (e) {
                //console.log(`error while building model ${args[0].value}`)
                console.log(`error while building model`)
                console.error(e)
            }
            return
        }

        if (address === '/load_ledger') {
          //console.log(args[0].value)
          resourceDir = args[0].value.replace(/\.[^/.]+$/, "");
          receive('/ledger', JSON.stringify(loadJSON(args[0].value).ledger, null, '  ').replace(/['"]+/g, ''))
          return data
        }

        if (address === '/save_ledger') {
          resourceDir = args[0].value.replace(/\.[^/.]+$/, "");
          ledger = {}
          ledger.ledger = JSON.parse(args[0].value.replace(/([a-zA-Z0-9-]+)/g, "\"$1\""))
          args[0].value = JSON.stringify(ledger)
          return {host, port, address, args}
        }

        if (address === '/commit') {
          var model = {}
          model.music_data = JSON.parse(args[0].value)
          args[0].value = JSON.stringify(model)
          return {host, port, address, args}
        }

				if (address === '/load_model_state') {
					id = args[0].value
					var modelPath = resolve(resourceDir + "/" + id + "/" + id + "_mus_model.json")
	        var model = loadJSON(modelPath)
					loadModel(model)
					return
        }

				if (address === '/transport') {
					if(args[0].value == 2){
	          var model = {}
	          model.music_data = JSON.parse(args[1].value)
	          args[1].value = JSON.stringify(model)
					}
          return {host, port, address, args}
        }

				if (address.substring(1, 6) == 'mixer') {
					tokens = address.split('/')
					ins = tokens[2]
					type = tokens[3]
					index = tokens[4]
					val = args[0].value
					args = [{'type': 's', 'value': ins}, {'type': 's', 'value': type}, {'type': 's', 'value': index}, {'type': 'f', 'value': val}]
          //console.log(data)
					address = '/mixer'
          return {host, port, address, args}
        }

				if (address === '/sampler') {
					return data
				}

				if (address === '/transcribe_motif') {
					var model = {}
					model.music_data = JSON.parse(args[0].value)
					args[0].value = JSON.stringify(model)
          return {host, port, address, args}
				}

				if (address === '/transcribe_all') {
					return data
				}

        /*
				if (['/mixer'].includes(address)) {
          console.log(data)
          return data
        }
				*/


        return

    },

    unload: function(){
        // this will be executed when the custom module is reloaded
    },

}
