from flask import Flask, render_template, send_file, redirect, request
import os
from predict import generate_music
import uuid
from itertools import islice
from music21 import instrument, note, stream, chord,converter
from ga import selection_pair,single_point_crossover, mutation


app = Flask(__name__)

@app.route('/')
def home():
   return render_template('home.html')
@app.route('/upload')
def upload():
   return render_template('upload.html')

@app.route('/generateMusic')
def generateMusic():
   id=str((uuid.uuid4()))
   for i in range(5):
      generate_music(id)
   return redirect('/rateMusic/'+id)
   
@app.route('/rateMusic/<id>')
def rateMusic(id):
    songs = os.listdir(os.path.join(app.static_folder, id))
    return render_template('rate.html', songs=songs,id=id)

@app.route('/handle_rate/<id>', methods=['POST'])
def handle_rate(id):
   
   songs = os.listdir(os.path.join(app.static_folder, id))
   songs_fitness={}
   songs_notes=[]
   for filename in songs:
      songs_fitness[filename]=request.form[filename+"/"]

      midi = converter.parse("static/"+id+"/"+filename) 
      notes=[]
      notes_to_parse = None
      #parsing notes from midi files
      try:
         s2 = instrument.partitionByInstrument(midi)
         notes_to_parse = s2.parts[0].recurse() 
      except:
         notes_to_parse = midi.flat.notes
      for element in notes_to_parse:
         if isinstance(element, note.Note):
               notes.append(str(element.pitch))
         elif isinstance(element, chord.Chord):
               notes.append('.'.join(str(n) for n in element.normalOrder))
      songs_notes.append(notes)
   songs_fitness={k: v for k, v in sorted(songs_fitness.items(), key=lambda item: int(item[1]),reverse=True)}
   
   ordered_songs = [e[0] for e in songs_fitness]
   for i in ordered_songs[2:]:
      if os.path.exists("static/"+id+"/"+filename):
         os.remove("static/"+id+"/"+filename)


   next_gen = []
   for j in range(int(len(ordered_songs) / 2) - 1):
      def find_fitness(genome):
          for e in songs_fitness:
              if e[0] == genome:
                  return e[1]
          return 0

      parents = selection_pair(songs_notes, find_fitness)
      offspring_a, offspring_b = single_point_crossover(parents[0], parents[1])
      offspring_a = mutation(offspring_a, num=5, probability=0.5)
      offspring_b = mutation(offspring_b, num=5, probability=0.5)
      #make into file names instead
      next_gen += [offspring_a, offspring_b]
   #create midi files and remove old ones
   print(next_gen)
   offset = 0
   output_notes = []

   # create note and chord objects based on the values generated by the model
   for song in next_gen:
      # pattern is a chord
      for pattern in song:
         if ('.' in pattern) or pattern.isdigit():
               notes_in_chord = pattern.split('.')
               notes = []
               for current_note in notes_in_chord:
                  new_note = note.Note(int(current_note))
                  new_note.storedInstrument = instrument.Piano()
                  notes.append(new_note)
               new_chord = chord.Chord(notes)
               new_chord.offset = offset
               output_notes.append(new_chord)
         # pattern is a note
         else:
               new_note = note.Note(pattern)
               new_note.offset = offset
               new_note.storedInstrument = instrument.Piano()
               output_notes.append(new_note)

         # increase offset each iteration so that notes do not stack
         offset += 0.5

   midi_stream = stream.Stream(output_notes)
   name='static/'+id+'/music-'+str((uuid.uuid4()))+'.mid'
   midi_stream.write('midi', fp=name)
   songs = os.listdir(os.path.join(app.static_folder, id))
   return render_template('results.html',id=id, songs=songs)



if __name__ == '__main__':
   app.run(debug=True)