//
//  TrainingMessageOrganiser.mm
//  riftathon
//
//  Created by Robert Tubb on 17/10/2014.
//
//

#include "TrainingMessageOrganiser.h"

void TrainingMessageOrganiser::init( PDSynthWrapper& cs, PDSynthWrapper& ts){
    
    MessageOrganiser::init(cs,ts);
    
    TickListenerFunction callback;
    callback = boost::bind(&TrainingMessageOrganiser::onNextTick, this, _1);
    candidateSynth.registerForTicks(callback);
    
    numParamsToUse = TOTAL_NUM_PARAMS;
    
}

void TrainingMessageOrganiser::setMiddlePanel(TextPanel* tp){
    middlePanel = tp;
}

void TrainingMessageOrganiser::setupDefaultMapping(){
    vector<int> mappingIDsForChangeableParams = getMappingIDsFromSynths();
    
    controlPanelType cpt = REVISITABLE;
    vector<controllerType> elemList;
    for(int i = 0; i < numParamsToUse; i++){
        elemList.push_back(SLIDER);
    }
    
    vector<UIElement*> UIElemHandles = panel->generateControls(elemList, cpt);
    
    mapSlidersToParams(UIElemHandles, mappingIDsForChangeableParams);
    
    bottomPanel->show();
    
    ofColor c = ofColor::yellow;
    panel->setHintColor(c);
}

vector<int> TrainingMessageOrganiser::getMappingIDsFromSynths(){
    vector<int> index;
    for(int i = 0; i < numParamsToUse; i++){
        index.push_back(i);
    }
    vector<int> mids = candidateSynth.getMappingIDForIndices(index);
    
    return mids;
}

void TrainingMessageOrganiser::showMyPanels(){
    presetIconPanel->show();
    instructionPanel->show();
    bottomPanel->show();
    panel->hide();
    middlePanel->show();
}

//-----------------------------------------------------------------------
void TrainingMessageOrganiser::displayInstructions(Step s){
    
    
    if (s.type == Step::COUNT_IN){
        instructionPanel->setText("COUNT_IN" + ofToString(downCounter));
        middlePanel->setText(ofToString(downCounter));
    }
    if (s.type == Step::PREVIEW_PREPARER){
        instructionPanel->setText("PREVIEW_PREPARER");
        panel->setColor(ofColor(0,0,0));
    }
    
    if (s.type == Step::PREVIEW_DISPLAYER){
        instructionPanel->setText("PREVIEW_DISPLAYER");
        panel->setColor(ofColor(0,0,0));
    }
    if (s.type == Step::MATCHING_PREPARER){
        instructionPanel->setText("MATCHING_PREPARER");
        middlePanel->setText(ofToString(downCounter));
        panel->setColor(ofColor(250,0,0));
    }
    if (s.type == Step::MATCHING_INTERACTION){
        instructionPanel->setText("MATCHING_INTERACTION!!!!");
        panel->setColor(ofColor(250,0,0));
    }
    if (s.type == Step::MATCHING_RESULT){
        instructionPanel->setText("RESULT");
        panel->setColor(ofColor(0,0,0));
    }
}
//-----------------------------------------------------------------------
void TrainingMessageOrganiser::onNextTick(int tickNumber){
    static int showingCountdown = false;
    cout << "TICK " << tickNumber << endl;
    downCounter = 4 - tickNumber % 4;
    
    if (showingCountdown){
        middlePanel->setColor(ofColor::white);
        middlePanel->setText(ofToString(downCounter));
    }
    
    // only first beat in bar is active one
    if ( tickNumber % 4  != 0){
        
        return;
    }
    // load next target preset
    
    Step newStep = sequenceController.getNextStep();
    displayInstructions(newStep);
    
    if(newStep.isLastOfAll){
        // do finished run stuff, show summary
        candidateSynth.stopMetronome();
        cout << "FINISHED BLOCK" << endl;
        panel->hide();
        middlePanel->setColor(ofColor::white);
        middlePanel->setText("FINISHED BLOCK");
        return;
    }
    if(newStep.isLastOfRun){
        // do finished run stuff, show summary
        candidateSynth.stopMetronome();
        cout << "FINISHED RUN" << endl;
        panel->hide();
        middlePanel->setColor(ofColor::white);
        middlePanel->setText("FINISHED RUN");
        middlePanel->show();
        return;
    }

    candidateSynth.setMetroTime(newStep.getTimeBetweenTicks());
    
    if(newStep.showsCountDown){
        // count in
        showingCountdown = true;
        middlePanel->show();
    }else{
        showingCountdown = false;
    }
    
    Preset * currentTargetPreset;
    
    if(newStep.presetIndex >= 0 && newStep.presetIndex <= 8){
        currentTargetPreset =  expPresetManager.getPresetAtIndex(newStep.presetIndex);
    }else{
        assert(newStep.type == Step::COUNT_IN);
        // nothing happens here
        return;
    }

    vector<int> newTargetValues = currentTargetPreset->getValues();
    debugVals(newTargetValues);
    
    if(newStep.hidesSliders){
        panel->hide();
        middlePanel->setBackground(ofColor(255,0,0));
        middlePanel->show();
    }else{
        panel->show();
        middlePanel->hide();
    }
    
    if(newStep.showsTargetIcon){
        bool showTick = true;
        presetIconPanel->setTextAndImage(currentTargetPreset->name, currentTargetPreset->getImage(), showTick);
        presetIconPanel->show();
        box6D->setHintTexture(currentTargetPreset->getImage());
    }else{
        presetIconPanel->hide();
    }
    
    if(newStep.allowsCandidateControl){
        setCandidateAndSlidersToRandom();
        panel->setActive(true);
        okToGetMidi = true;
    }else{
        panel->setActive(false);
        okToGetMidi = false;
    }
    
    if(newStep.showsControlSettings){
        // actually alters the slider values
        targetSynth.setAllParams(newTargetValues);
        setAllSlidersToValues(newTargetValues);
        box6D->setValues(newTargetValues);
    }else{
        
        
    }
    
    panel->setHintValues(newTargetValues);
    box6D->setHintValues(newTargetValues);
    
    if(newStep.showsControlGuides){
        // shows visual target lines on sliders (or target hand in VR)
        
        panel->showHint(true);
        box6D->showHint(true);
    }else{
        panel->showHint(false);
        box6D->showHint(false);
    }
    
    
    if(newStep.showsMatchResults){
        // do something
        //newStep->calculateResults();
        TrainingTestResult result =
            trainingScoreManager.getScoreForAnswer(candidateSynth.getAllParamValues(),
                                                   newTargetValues,
                                                   newStep.getTimeBetweenTicks());
        
        
        //middlePanel->setLabel(result.displayText);
        middlePanel->setColor(result.colorBand);
        middlePanel->setText(result.displayText);
        panel->setHintColor(result.colorBand);
        panel->showHint(true);
        middlePanel->show();
    }else{
        middlePanel->setText("");
    }
    
    if(newStep.playsTarget){
        targetSynth.setAllParams(newTargetValues);
        targetSynth.trigger();
    }
    if(newStep.playsCandidate){
        triggerCandidateSound();
    }
    
}

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

void TrainingMessageOrganiser::showUserHowTheyDid(){
    // colour flash
    // distance ?
    // score
    
}

//-----------------------------------------------------------------------------
void TrainingMessageOrganiser::midiFromLeap(int ctl_num, int ctl_val){
    
    if (!okToGetMidi){
        return;
    }
    vector<int> mids = candidateSynth.getAllMappingIDs();
    if (ctl_num >= mids.size() || ctl_num < 0) return;
    
    paramChangeCallback(mids[ctl_num], ctl_val );
    
    //candidateSynth.paramChangeCallback(mids[ctl_num], ctl_val);
    
    setUIToParam(ctl_num, ctl_val);
    
    vector<int> evtData;
    evtData.push_back(mids[ctl_num]); // or just index?
    evtData.push_back(ctl_val);
    
    eventLogger.logEvent(CANDIDATE_PARAM_ADJUSTED, evtData);
    
}
//-----------------------------------------------------------------------------

void TrainingMessageOrganiser::buttonPressCallback(int mappingID, int value){
    if(mappingID == VOLUME_CHANGE_ID){
        targetSynth.sendVolume(value);
        candidateSynth.sendVolume(value);
        return;
    }
    
    if (mappingID == TRIGGER_CANDIDATE_ID){
        //triggerCandidateSound();
        // compare to target
        candidateSynth.setMetroTime(sequenceController.getStartTickTime());
        candidateSynth.startMetronome();
        return;
    }
    
}
//-----------------------------------------------------------------------------
