//
//  SequenceGenerator.mm
//  riftathon
//
//  Created by Robert Tubb on 21/10/2014.
//
//

#include "SequenceController.h"
AnimStep::AnimStep(){
    type = PREVIEW_NEUTRAL_COUNT;
    presetIndex = -1;
    seqNumber = -1;
    runNumber = -1;
    whichInSequence = -1;
    
    tempo = MIN_TEMPO;
    
    isLastOfSeq = false;
    isLastOfRun = false;
    isLastOfAll = false;
    
    showsGuides = false;
}
Step::Step(){
    type = COUNT_IN;
    
    showsTargetIcon = false;
    showsControlSettings = false;
    showsControlGuides = false;
    showsMatchResults = false;
    hidesSliders = true;
    isPreview = false;
    
    allowsCandidateControl = false;
    playsTarget = false;
    playsCandidate = false;
    
    showsCountDown = true;
    
    isLastOfSeq = false;
    isLastOfRun = false;
    isLastOfAll = false;
    presetIndex = -1;
    seqNumber = -1;
    runNumber = -1;
    
    tempo = MIN_TEMPO;
}
void Step::setAsBlankCounter(){
    type = COUNT_IN;
    showsTargetIcon = false;
    showsControlSettings = false;
    showsControlGuides = false;
    showsMatchResults = false;
    hidesSliders = true;
    isPreview = false;
    
    allowsCandidateControl = false;
    playsTarget = false;
    playsCandidate = false;
    showsCountDown = true;
    
}
void Step::setAsPreviewPreparer(){
    type = PREVIEW_PREPARER;
    showsTargetIcon = true;
    showsControlSettings = false;
    showsControlGuides = true;
    
    showsMatchResults = false;
    hidesSliders = true;
    isPreview = true;
    
    allowsCandidateControl = true;
    playsTarget = true;
    playsCandidate = false;
    showsCountDown = true;
}

void Step::setAsPreviewPlayer(){
    type = PREVIEW_DISPLAYER;
    showsTargetIcon = true;
    showsControlSettings = false;
    showsControlGuides = true;
    showsMatchResults = false;
    hidesSliders = false;
    
    isPreview = true;
    
    allowsCandidateControl = true;
    playsTarget = true;
    playsCandidate = false;
    
    showsCountDown = false;
}

void Step::setAsMatchingPreparer(){
    // just a count down
    type = MATCHING_PREPARER;
    showsTargetIcon = true;
    showsControlSettings = false;
    showsControlGuides = false;
    showsMatchResults = false;
    hidesSliders = true;
    
    isPreview = false;
    
    allowsCandidateControl = true;
    playsTarget = true;
    playsCandidate = false;
    
    showsCountDown = true;
}
void Step::setAsMatchingInteraction(){
    type = MATCHING_INTERACTION;
    showsTargetIcon = true;
    showsControlSettings = false;
    showsControlGuides = true;
    showsMatchResults = false;
    hidesSliders = false;
    isPreview = false;
    
    allowsCandidateControl = true;
    playsTarget = false;
    playsCandidate = false; // ??
    
    showsCountDown = false;
}
void Step::setAsMatchingFeedback(){
    type = MATCHING_INTERACTION;
    showsTargetIcon = false;
    showsControlSettings = false;
    showsControlGuides = false;
    showsMatchResults = true;
    hidesSliders = true;
    isPreview = false;
    
    allowsCandidateControl = false;
    playsTarget = false;
    playsCandidate = true; // ??
    
    showsCountDown = false;
}

//=================================================================
//=================================================================
//=================================================================

SequenceController::SequenceController(){
    tempoInc = float(MAX_TEMPO - MIN_TEMPO) / float(NUM_TEMPO_STEPS);
    generateSteps();
    setToStart();
};
AnimStep SequenceController::getNextStep(){
    
    currentStep++;
    if ((*currentStep).isLastOfRun){
        // uh
    }
    if ((*currentStep).isLastOfSeq){
        
    }
    return (*currentStep);
    
};
//-------------------------------------------------------------------
void SequenceController::setToStart(){
    currentStep = steps.begin();
}
//-------------------------------------------------------------------
void SequenceController::stepForward(){
    currentStep++;
};
//-------------------------------------------------------------------
float SequenceController::getStartTickTime(){
    return 1000. * (60.0/MIN_TEMPO);
}
//-------------------------------------------------------------------
void SequenceController::generateSteps(){
    srand (time(NULL));
    
    int run = 0;
    
    
    
    for(int numInSequence = MIN_TARGETS_IN_SEQUENCE; numInSequence <= MAX_TARGETS_IN_SEQUENCE; numInSequence++){
        generateCountIn(2);
        generateARun(run, numInSequence);
        
        steps.back().isLastOfRun = true;
        run++;
        cout << "-generate run finished-" << endl;
    }
    steps.back().isLastOfAll = true;
};

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


void SequenceController::generateCountIn(int countInLength){
    AnimStep countStep;
    for (int i = 0; i < countInLength; i++){
        countStep.whichInSequence = countInLength - i + 1;
        countStep.type = AnimStep::PREVIEW_NEUTRAL_COUNT;
        steps.push_back(countStep);
        
    }
};

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


vector<int> SequenceController::randomSequence(int numInSequence){
    vector<int> stepPresetIndices;
    // get some random ints
    for(int n=0; n < numInSequence; n++){
        int nextPreset = getRandomButNot(NUM_PRESETS,stepPresetIndices);
        stepPresetIndices.push_back(nextPreset);
        cout << nextPreset << ",";
    }
    
    return stepPresetIndices;
}

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

void SequenceController::generateARun(int run, int numInSequence){
    float curTempo = MIN_TEMPO;
    int seqNo = 0;
    AnimStep nextStep;
    for(int tempoLevel = 0; tempoLevel < NUM_TEMPO_STEPS; tempoLevel++){
        
        
        
        // first we have a preparation count in
        nextStep.presetIndex = -1; // minus one means "blank"
        nextStep.runNumber = run;
        nextStep.seqNumber = seqNo;
        nextStep.whichInSequence = 0;
        nextStep.tempo = curTempo;
        nextStep.showsGuides = true;
        nextStep.type = AnimStep::PREVIEW_NEUTRAL_COUNT;
        steps.push_back(nextStep);
        
        // generate a sequence of random preset indices
        vector<int> stepPresetIndices = randomSequence(numInSequence);
        nextStep.thisSequence = stepPresetIndices;

        // make preview sequence
        int n = 1;
        for(auto si = stepPresetIndices.begin(); si < stepPresetIndices.end(); si++){
            // put loader
            
            nextStep.presetIndex = *si;
            nextStep.runNumber = run;
            nextStep.seqNumber = seqNo;
            nextStep.whichInSequence = n;
            nextStep.tempo = curTempo;
            nextStep.showsGuides = true;
            nextStep.type = AnimStep::PREVIEW_MOVE;
            steps.push_back(nextStep);
            
            if (SPACER_BARS){
                nextStep.type = AnimStep::PREVIEW_HIT;
                steps.push_back(nextStep);
            }
            n++;
        }
        
        nextStep.type = AnimStep::MATCHING_NEUTRAL_COUNT;
        steps.push_back(nextStep);
        
        // put in matching sequence
        n = 0;
        for(auto si = stepPresetIndices.begin(); si < stepPresetIndices.end(); si++){
            // put loader
            
            nextStep.presetIndex = *si;
            nextStep.whichInSequence = n;
            if (NO_GUIDES_LEVEL){
                nextStep.showsGuides = false;
            }else{
                nextStep.showsGuides = true;
            }
            nextStep.type = AnimStep::MATCHING_MOVE;
            steps.push_back(nextStep);
            
            if (SPACER_BARS){
                nextStep.type = AnimStep::MATCHING_HIT;
                steps.push_back(nextStep);
            
            }
            n++;

        }
        
        steps.back().isLastOfSeq = true;
        curTempo += tempoInc;
        seqNo++;
        cout << endl;
        
    }
    // ANIM nextStep.setAsBlankCounter();
    nextStep.type = AnimStep::MATCHING_NEUTRAL_COUNT;
    steps.push_back(nextStep);
    
}
//-----------------------------------------------------------------------


int SequenceController::getRandomButNot(int max, vector<int> notThese){
    
    bool there = true;
    int randomInt = rand() % max;
    
    if (notThese.size()){
        while(there){
            randomInt = rand() % max;
            vector<int>::iterator result = std::find(notThese.begin(), notThese.end(), randomInt);
            there =  (result != notThese.end());
        }
    }
    return randomInt;
    
};