//
//  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::onNextTickAnim, this, _1);
    candidateSynth.registerForTicks(callback);
    
    numParamsToUse = TOTAL_NUM_PARAMS;
    
}

void TrainingMessageOrganiser::setup(controlPanelType whichInterfaceAreWeUsing){
    
    setupDefaultMapping(whichInterfaceAreWeUsing);
    
    
}
//----------------------------------------------------------------------------------------
void TrainingMessageOrganiser::setMiddlePanel(TextPanel* tp){
    middlePanel = tp;
}

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

//-----------------------------------------------------------------------
void TrainingMessageOrganiser::displayInstructions(string text){

    instructionPanel->setText(text);
    instructionPanel->show();

}

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

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;
    }
    
}
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------
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;
     controlPanel->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;
     controlPanel->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){
     controlPanel->hide();
     middlePanel->setBackground(ofColor(255,0,0));
     middlePanel->show();
     }else{
     controlPanel->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();
     controlPanel->setActive(true);
     okToGetMidi = true;
     }else{
     controlPanel->setActive(false);
     okToGetMidi = false;
     }
     
     if(newStep.showsControlSettings){
     // actually alters the slider values
     targetSynth.setAllParams(newTargetValues);
     setAllSlidersToValues(newTargetValues);
     box6D->setValues(newTargetValues);
     }else{
     
     
     }
     
     controlPanel->setHintValues(newTargetValues);
     box6D->setHintValues(newTargetValues);
     
     if(newStep.showsControlGuides){
     // shows visual target lines on sliders (or target hand in VR)
     
     controlPanel->showHint(true);
     box6D->showHint(true);
     }else{
     controlPanel->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);
     controlPanel->setHintColor(result.colorBand);
     controlPanel->showHint(true);
     middlePanel->show();
     }else{
     middlePanel->setText("");
     }
     
     if(newStep.playsTarget){
     targetSynth.setAllParams(newTargetValues);
     targetSynth.trigger();
     }
     if(newStep.playsCandidate){
     triggerCandidateSound();
     }
     */
    
}
void TrainingMessageOrganiser::lastOfRun(){
    candidateSynth.stopMetronome();
    cout << "FINISHED RUN" << endl;
    controlPanel->hide();
    middlePanel->setColor(ofColor::white);
    middlePanel->setText("FINISHED RUN");
    middlePanel->show();
}
void TrainingMessageOrganiser::lastOfAll(){
    candidateSynth.stopMetronome();
    cout << "FINISHED RUN" << endl;
    controlPanel->hide();
    middlePanel->setColor(ofColor::white);
    middlePanel->setText("FINISHED RUN");
    middlePanel->show();
}
//-----------------------------------------------------------------------------
void TrainingMessageOrganiser::onNextTickAnim(int tickNumber){
    
    cout << "TICK " << tickNumber << endl;
    downCounter = 4 - tickNumber % 4;
    
    updateCountdown(downCounter);
    // only first beat in bar is active one (at the moment)
    if ( tickNumber % 4  != 0) return;
    
    
    AnimStep newStep = sequenceController.getNextStep();
    
    if(newStep.isLastOfAll){
        lastOfAll();
        return;
    }
    if(newStep.isLastOfRun){
        lastOfRun();
        return;
    }
    
    candidateSynth.setMetroTime(newStep.getTimeBetweenTicks());
    
    switch (newStep.type){
        case AnimStep::PREVIEW_NEUTRAL_COUNT :
            previewNeutralCount(newStep);
            break;
        case AnimStep::PREVIEW_MOVE :
            previewMove(newStep);
            break;
        case AnimStep::PREVIEW_HIT :
            previewHit( newStep);
            break;
        case AnimStep::MATCHING_NEUTRAL_COUNT :
            matchingNeutralCount( newStep);
            break;
        case AnimStep::MATCHING_MOVE :
            matchingMove( newStep);
            break;
        case AnimStep::MATCHING_HIT :
            matchingHit( newStep);
            break;
    }
    
}
//-----------------------------------------------------------------------------
void TrainingMessageOrganiser::updateCountdown(int n){
    
}
//-----------------------------------------------------------------------------
void TrainingMessageOrganiser::previewNeutralCount(AnimStep newStep){
    
    middlePanel->hide();
    
    Preset * currentTargetPreset;
    
    // show eveything at start?
    showMyPanels();
    // your 'hand' is hidden
    controlPanel->showValueIndicators(false);
    
    
    // guide is set to neutral values
    currentTargetPreset = expPresetManager.getNeutralPreset();
    vector<int> newTargetValues = currentTargetPreset->getValues();
    presetIconPanel->setTextAndImage(currentTargetPreset->name, currentTargetPreset->getImage(), false);
    presetIconPanel->show();
    
    controlPanel->setAndShowHint(newTargetValues, currentTargetPreset->getImage());

    
    targetSynth.setAllParams(newTargetValues);
    candidateSynth.setAllParams(newTargetValues);
    
    displayInstructions("preview Neutral Count");
}
//-----------------------------------------------------------------------------
void TrainingMessageOrganiser::previewMove(AnimStep newStep){
    Preset * currentTargetPreset;
    currentTargetPreset =  expPresetManager.getPresetAtIndex(newStep.presetIndex);
    vector<int> newTargetValues = currentTargetPreset->getValues();
    
    targetSynth.setAllParams(newTargetValues);
    
    presetIconPanel->setTextAndImage(currentTargetPreset->name, currentTargetPreset->getImage(), false);
    presetIconPanel->show();
    controlPanel->show();
    // your hand is hidden
    controlPanel->showValueIndicators(false);
    // guide animates to next target

    //controlPanel->setAndShowHint(newTargetValues, currentTargetPreset->getImage());
    controlPanel->animateToNewHintValues(newTargetValues, newStep.getTimeBetweenTicks()*4, currentTargetPreset->getImage());
    displayInstructions("preview Move");
}
//-----------------------------------------------------------------------------
void TrainingMessageOrganiser::previewHit(AnimStep newStep){
    Preset * currentTargetPreset;
    currentTargetPreset =  expPresetManager.getPresetAtIndex(newStep.presetIndex);
    vector<int> newTargetValues = currentTargetPreset->getValues();
    
    targetSynth.setAllParams(newTargetValues);
    
    // your hand hidden
    controlPanel->showValueIndicators(false);
    //
    presetIconPanel->setTextAndImage(currentTargetPreset->name, currentTargetPreset->getImage(), false);
    presetIconPanel->show();
    
    controlPanel->setAndShowHint(newTargetValues, currentTargetPreset->getImage());

    
    targetSynth.trigger();
    
    displayInstructions("Preview HIT");
}
//-----------------------------------------------------------------------------
void TrainingMessageOrganiser::matchingNeutralCount(AnimStep newStep){
    Preset * currentTargetPreset = expPresetManager.getNeutralPreset();
    vector<int> newTargetValues = currentTargetPreset->getValues();
    // if showing guides show all the targets as transparent ghosts
    if (newStep.showsGuides){
        controlPanel->setAndShowHint(newTargetValues, currentTargetPreset->getImage());

    }else{
        controlPanel->showHint(false);
    }
    
    // show your hand and allow movement
    controlPanel->showValueIndicators(true);
    okToGetMidi = true;
    
        displayInstructions("Match Count");
}
//-----------------------------------------------------------------------------
void TrainingMessageOrganiser::matchingMove(AnimStep newStep){
    middlePanel->hide();
    
    Preset * currentTargetPreset;
    currentTargetPreset =  expPresetManager.getPresetAtIndex(newStep.presetIndex);
    vector<int> newTargetValues = currentTargetPreset->getValues();
    
    targetSynth.setAllParams(newTargetValues);
    
    controlPanel->setHintColor(ofColor::white);
    
    // if showing guides show all the targets as transparent ghosts
    if (newStep.showsGuides){
        presetIconPanel->setTextAndImage(currentTargetPreset->name, currentTargetPreset->getImage(), false);
        presetIconPanel->show();
        
        controlPanel->setAndShowHint(newTargetValues, currentTargetPreset->getImage());
    }else{
        presetIconPanel->hide();
        controlPanel->showHint(false);
    }
    
    // show your hand and allow movement
    //controlPanel->showIndicator(true);
    okToGetMidi = true;
    
    displayInstructions("Match MOVE");



}
//-----------------------------------------------------------------------------
void TrainingMessageOrganiser::matchingHit(AnimStep newStep){
    Preset * currentTargetPreset;
    currentTargetPreset =  expPresetManager.getPresetAtIndex(newStep.presetIndex);
    vector<int> newTargetValues = currentTargetPreset->getValues();

    sendSynthValuesAgain();
    
    // show your hand and allow movement (so you can set off to next target??)
    //box6D->showIndicator(true);
    okToGetMidi = true;
    
    targetSynth.setAllParams(newTargetValues);
    triggerCandidateSound();
    
    displayInstructions("Match HIT");
    
    
    TrainingTestResult result =
    trainingScoreManager.getScoreForAnswer(candidateSynth.getAllParamValues(),
                                           newTargetValues,
                                           newStep.getTimeBetweenTicks());
    
    
    //middlePanel->setLabel(result.displayText);
    instructionPanel->setColor(result.colorBand);
    //middlePanel->setText(result.displayText);
    
    // show where you should have been
    controlPanel->setHintColor(result.colorBand);
    presetIconPanel->setTextAndImage(currentTargetPreset->name, currentTargetPreset->getImage(), false);
    presetIconPanel->show();
    controlPanel->setAndShowHint(newTargetValues, currentTargetPreset->getImage());

    controlPanel->flashResultLight(result.colorBand, newStep.getTimeBetweenTicks());
    middlePanel->show();
    displayInstructions(result.displayText);
}

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