//--------------------------------------------------------------
void testApp::setup()
{
	ofSetFrameRate(60);
	ofSetVerticalSync(true);
	
	ofBackground(0);
	
	keyValue.setup(5500);

	params.setName("params");
  params.add( param1.set("param1float", 0.5f) );
  params.add( param2.set("param2bool", false) );
  params.add( param3.set("param3vec2", ofVec2f(0.1,0.2)) );
}
ofxGuiPanel::ofxGuiPanel(const ofParameterGroup & parameters, const ofJson & config)
:ofxGuiPanel(parameters.getName()){

	addParametersFrom(parameters);
	_setConfig(config);

}
ofxGuiContainer::ofxGuiContainer(const ofParameterGroup & _parameters, const ofJson & config)
    :ofxGuiContainer(_parameters.getName()) {

    addParametersFrom(_parameters);
    _setConfig(config);

}
ofxGuiContainer::ofxGuiContainer(const ofParameterGroup & _parameters, const std::string& _filename, float x, float y)
    :ofxGuiContainer(_parameters.getName()) {

    filename = _filename;
    setPosition(x,y);
    addParametersFrom(_parameters);

}
ofxGuiPanel::ofxGuiPanel(const ofParameterGroup & parameters, const std::string& filename, float x, float y)
	:ofxGuiPanel(parameters.getName()){

	addParametersFrom(parameters);
//	config.filename = filename;
	// TODO set filename
	setPosition(x,y);

}
//--------------------------------------------------------------
void testApp::update()
{
	
	// get value directly
	
	string s;
	if (keyValue.get("/string_value", s))
	{
		cout << "/string_value: " << s << endl;
	}
	
	
	// get value as osc message
	
	ofxOscMessage m;
	if (keyValue.get("/test", m))
	{
		cout << "/test: " << m.getArgAsFloat(0) << endl;
	}
	
	
	// use Key-Value-Store style address

	keyValue.get("/myObject1.pos", myObject1.pos);
	keyValue.get("/myObject1.color", myObject1.color);


  for (int i = 0; i < params.size(); i++)
  {
    string name = "/"+params.getName(i);
    if ( keyValue.get( name, params.get(i) ) )
      cout << "update param " << name << " = " << params.get(i) << endl;
  }

	
	// FIFO queue access
	
	int value;
	while (keyValue.get("/uzi", value))
	{
		printf("%i\n", value);
	}

}
//--------------------------------------------------------------
void ofShader::setUniforms(const ofParameterGroup & parameters) const{
	for(int i=0;i<parameters.size();i++){
		if(parameters[i].type()==typeid(ofParameter<int>).name()){
			setUniform1i(parameters[i].getEscapedName(),parameters[i].cast<int>());
		}else if(parameters[i].type()==typeid(ofParameter<float>).name()){
			setUniform1f(parameters[i].getEscapedName(),parameters[i].cast<float>());
		}else if(parameters[i].type()==typeid(ofParameter<ofVec2f>).name()){
			setUniform2f(parameters[i].getEscapedName(),parameters[i].cast<ofVec2f>());
		}else if(parameters[i].type()==typeid(ofParameter<ofVec3f>).name()){
			setUniform3f(parameters[i].getEscapedName(),parameters[i].cast<ofVec3f>());
		}else if(parameters[i].type()==typeid(ofParameter<ofVec4f>).name()){
			setUniform4f(parameters[i].getEscapedName(),parameters[i].cast<ofVec4f>());
		}else if(parameters[i].type()==typeid(ofParameterGroup).name()){
			setUniforms((ofParameterGroup&)parameters[i]);
		}
	}
}
void ofxParameterTwister::setParams(const ofParameterGroup& group_)
{
	ofLogVerbose() << "Updating mapping" << endl;
	/*

	based on incoming parameters,
	we set our Encoders to track them

	*/

	auto it = group_.begin();
	auto endIt = group_.end();

	for (auto & e : mEncoders) {

		if (it != endIt) {
			if (auto param = dynamic_pointer_cast<ofParameter<float>>(*it)) {
				// bingo, we have a float param
				e.setState(Encoder::State::ROTARY);
				e.setValue(ofMap(*param, param->getMin(), param->getMax(), 0, 127, true));

				// now set the Encoder's event listener to track 
				// this parameter
				auto pMin = param->getMin();
				auto pMax = param->getMax();

				e.updateParameter = [=](uint8_t v_) {
					// on midi input
					param->set(ofMap(v_, 0, 127, pMin, pMax, true));
				};

				e.mELParamChange = param->newListener([&e, pMin, pMax](float v_) {
					// on parameter change, write from parameter 
					// to midi.
					e.setValue(ofMap(v_, pMin, pMax, 0, 127, true));
				});

			} else if (auto param = dynamic_pointer_cast<ofParameter<bool>>(*it)) {
				// we have a bool parameter
				e.setState(Encoder::State::SWITCH);
				e.setValue((*param == true) ? 127 : 0);
				
				e.updateParameter = [=](uint8_t v_) {
					param->set((v_ > 63) ? true : false);
				};

				e.mELParamChange = param->newListener([&e](bool v_) {
					e.setValue(v_ == true ? 127 : 0);
				});

			} else {
				// we cannot match this parameter, unfortunately
				e.setState(Encoder::State::DISABLED);
				e.mELParamChange = ofEventListener(); // reset listener
			}
			
			it++;

		} else {
			// no more parameters to map.
			e.setState(Encoder::State::DISABLED, true);
		}
	}

}
//infer uniform type from structure of ofParameterGroup g
//and set in shader from values in g.
//assumes shader->begin() has been called already
void ofxBaseShaderNode::setShaderParam(ofParameterGroup &g){
    size_t dim = g.size();

    //need to infer the uniform type from size of, and types in, this group
    //unfortunately g.getType(0) is weird and compiler dependent, so this.
    //weep for me, weep for c++
    string type = "";
    if(g.contains("0i"))
        type = "int";
    else if(g.contains("0f"))
        type = "float";

    string param_name = g.getName();

    // cout<<"node "<<name<<" setting "<<type<<" "<<dim<<" uniform "<<param_name<<endl;

    if(type=="float"){
        // cout<<g.getFloat("0f")<<endl;
        switch(dim){
            case 1:
                shader->setUniform1f(param_name, g.getFloat("0f"));
                break;
            case 2:
                shader->setUniform2f(param_name, g.getFloat("0f"), g.getFloat("1f"));
                break;
            case 3:
                shader->setUniform3f(param_name, g.getFloat("0f"), g.getFloat("1f"), g.getFloat("2f"));
                break;
            case 4:
                shader->setUniform4f(param_name, g.getFloat("0f"), g.getFloat("1f"), g.getFloat("2f"), g.getFloat("3f"));
        }
    }
    else if(type=="int"){
        switch(dim){
            case 1:
                shader->setUniform1i(param_name, g.getInt("0i"));
                break;
            case 2:
                shader->setUniform2i(param_name, g.getInt("0i"), g.getInt("1i"));
                break;
            case 3:
                shader->setUniform3i(param_name, g.getInt("0i"), g.getInt("1i"), g.getInt("2i"));
                break;
            case 4:
                shader->setUniform4i(param_name, g.getInt("0i"), g.getInt("1i"), g.getInt("2i"), g.getInt("3i"));
        }
    }
}