
#include "MessageOrganiser.h"

void MessageOrganiser::init(PDSynthWrapper& cs, PDSynthWrapper& ts){
    candidateSynth = cs;
    targetSynth = ts;
    
    onlyChangeCandidateOnTrigger = true;
}


void MessageOrganiser::setupDefaultMapping(controlPanelType whichInterfaceAreWeUsing){
    vector<int> mappingIDsForChangeableParams = getMappingIDsFromSynths();
    vector<controllerType> elemList;
    
    if (whichInterfaceAreWeUsing == ALL_SLIDERS){
        
        for(int i = 0; i < TOTAL_NUM_PARAMS; i++){
            elemList.push_back(SLIDER);
            
        }
    }else if (whichInterfaceAreWeUsing == LEAP6DOF){
        elemList.push_back(LEAP6D);
    }
    vector<UIElement*> UIElemHandles = controlPanel->generateControls(elemList, whichInterfaceAreWeUsing);
    
    mapSlidersToParams(UIElemHandles, mappingIDsForChangeableParams);
    
}


//----------------------------------------------------------------------------------------
vector<int> MessageOrganiser::getMappingIDsFromSynths(){
    vector<int> index;
    for(int i = 0; i < TOTAL_NUM_PARAMS; i++){
        index.push_back(i);
    }
    vector<int> mids = candidateSynth.getMappingIDForIndices(index);
    
    return mids;
}
// could template for ui element type??
void MessageOrganiser::mapButtonToAction(UIElement* control, int mappingID){
    UICallbackFunction callbackF;
    callbackF = boost::bind(&MessageOrganiser::buttonPressCallback, this, _1,_2);
    control->addHandler(callbackF, mappingID);
    currentMapping.insert(std::pair<int,UIElement*>(mappingID,control));
}


void MessageOrganiser::setControlPanel(SliderPanel* p){ // a bit specific??
    controlPanel = p;
    
};
void MessageOrganiser::setBottomPanel(ButtonPanel * ntb){
    bottomPanel = ntb;
};


void MessageOrganiser::setIconPanel(IconPanel * ip){
    presetIconPanel = ip;
}

void MessageOrganiser::setInstructionPanel(TextPanel * ip){
    instructionPanel = ip;
    instructionPanel->show();
}


//-----------------------------------------------------------------------------
void MessageOrganiser::hideMyPanels(){
    presetIconPanel->hide();
    instructionPanel->hide();
    bottomPanel->hide();
    controlPanel->hide();
}
void MessageOrganiser::showMyPanels(){
    presetIconPanel->show();
    instructionPanel->show();
    bottomPanel->show();
    controlPanel->show();
}

void MessageOrganiser::triggerCandidateSound(){
    // log event
    sendSynthValuesAgain();
    candidateSynth.trigger();
    eventLogger.logEvent(CANDIDATE_PLAYED);
    // flash panel?
    controlPanel->flash();
}

void MessageOrganiser::paramChangeCallback(int mappingID, int value){
    
    if(onlyChangeCandidateOnTrigger){
        candidateSynth.paramChangeCallback(mappingID, value, false);
    }else{
        candidateSynth.paramChangeCallback(mappingID, value, true);
    }
    
    vector<int> evtData;
    evtData.push_back(mappingID); // or just index?
    evtData.push_back(value);
    
    eventLogger.logEvent(CANDIDATE_PARAM_ADJUSTED, evtData);
};

void MessageOrganiser::sendSynthValuesAgain(){
    candidateSynth.sendAllParams();
    targetSynth.sendAllParams();
};


void MessageOrganiser::setAllSlidersToValues(vector<int> values){
    for(int i = 0; i < values.size(); i++){
        setUIToParam(i, values[i]);
    }
}
// we want to set UI object
void MessageOrganiser::setUIToParam(int index, int value){ // e.g. from MIDI incoming, will handle both box and sliders...
    // theXY->setValueAndScale(candidateSynth.getParamValueForID(mids[i]), candidateSynth.getParamValueForID(mids[i+1]));
    UIElement* elem;
    // get the element
    if(controlPanel->subElements.size() <= index){
        cout << "ERROR: index out of range for num sliders" << endl;
        return;
    }
    elem = controlPanel->subElements[index];
    if ( elem->getType() == SLIDER){
        ButtronSlider* theSlider = (ButtronSlider*)elem;
        theSlider->setValueAndScale(value);
        
    }else if ( elem->getType() == LEAP6D){
        Leap6DBox* theBox = (Leap6DBox*)elem;
        theBox->setValueAndScale(index, value);
    }

};


void MessageOrganiser::mapControlToParam(UIElement* control, int mappingID){
    
    UICallbackFunction callbackF;
    callbackF = boost::bind(&MessageOrganiser::paramChangeCallback, this, _1,_2);
    control->addHandler(callbackF, mappingID);
    // put in our map so we can send param values to gui
    currentMapping.insert(std::pair<int,UIElement*>(mappingID,control));
    cout << " Mapped control to ID: " << mappingID << "Name: " << candidateSynth.getNameForMappingID(mappingID) << endl;
    control->setLabel(candidateSynth.getNameForMappingID(mappingID));
};

//-----------------------------------------------------------------------------

void MessageOrganiser::mapSlidersToParams(vector<UIElement*> elems, vector<int> mids){
    
    vector<UIElement*>::iterator elit;
    vector<int> typeListLog;
    int i = 0;
    for(elit=elems.begin(); elit<elems.end();elit++){
        if ( (*elit)->getType() == SLIDER){
            if(i >= mids.size()){
                
                cout << "ERROR ERROR: too many controls for mapping IDs: " << mids.size() << endl;
            }
            
            ButtronSlider* theSlider = (ButtronSlider*)(*elit);
            mapControlToParam((*elit), mids[i]);
            theSlider->setValueAndScale(candidateSynth.getParamValueForID(mids[i]));
            cout << "Hint Value " << targetSynth.getParamValueFromName(candidateSynth.getNameForMappingID(mids[i])) << endl;
            theSlider->setHintValue(targetSynth.getParamValueFromName(candidateSynth.getNameForMappingID(mids[i])));
            i++;
            typeListLog.push_back(int(SLIDER));
            
        }else{
            cout << "ERROR ERROR: ui type not handled my mapping function !" << endl;
        }
    }
    
    eventLogger.logEvent(CONTROL_LIST,typeListLog);
};

void MessageOrganiser::mapXYToParams(ButtronXY* control, int mappingIDX, int mappingIDY){
    UICallbackFunction callback;
    
    callback = boost::bind(&MessageOrganiser::paramChangeCallback, this, _1,_2);
    
    control->addHandler(callback, mappingIDX, mappingIDY);
    
    // put in our map so we can send param values to gui
    //currentMapping.insert(std::pair<int,UIElement*>(mappingID,control));
    
    
    cout << " Mapped control to XID: " << mappingIDX << "Name: " << candidateSynth.getNameForMappingID(mappingIDX) << endl;
    cout << " Mapped control to YID: " << mappingIDY << "Name: " << candidateSynth.getNameForMappingID(mappingIDY) << endl;
    control->setLabel(candidateSynth.getNameForMappingID(mappingIDX), candidateSynth.getNameForMappingID(mappingIDY));
    
};


void MessageOrganiser::mapControlToParam(UIElement* control, string paramName){
    // get mapping ID from synth
    int mappingID = candidateSynth.getMappingIDForName(paramName);
    mapControlToParam(control, mappingID);
    control->setLabel(paramName);
};

void MessageOrganiser::buttonPressCallback(int mappingID, int value){
    
};


void MessageOrganiser::setSlidersToTarget(){
    // this will actually show sliders with target vals - for "memorisation" purposes mwa heh heh
    // get target values
    // set ui
    vector<int> vals = targetSynth.getAllParamValues();
    for(int i=1; i < vals.size(); i++){
        setUIToParam(i, vals[i]);
    }
}
void MessageOrganiser::showTargetAsHints(){
//    int i = 0;
//    vector<int> vals = targetSynth.getAllParamValues();
//    for(auto elit=elems.begin(); elit<elems.end();elit++){
//        ButtronSlider* theSlider = (ButtronSlider*)(*elit);
//        theSlider->setHintValue(vals[i]);
//        i++;
//    }
}
void MessageOrganiser::setSlidersToDefault(){
    for(int i=1; i < candidateSynth.getNumParams(); i++){
        setUIToParam(i, 0);
        
    }
}
void MessageOrganiser::setCandidateAndSlidersToRandom(){
    vector<int> rands;
    for(int i = 0; i < candidateSynth.getNumParams(); i++){
        
        rands.push_back(rand() % 127);
    }
    
    setAllSlidersToValues(rands);
    candidateSynth.setAllParams(rands);
    
}