package inpro.synthesis.hts;

import inpro.incremental.util.TTSUtil.SynthesisPayload;
import inpro.synthesis.MaryAdapter5internal;

import java.util.ArrayList;
import java.util.List;

import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;

import org.w3c.dom.Element;

import marytts.datatypes.MaryData;
import marytts.htsengine.HMMVoice;
import marytts.htsengine.HTSParameterGeneration;
import marytts.htsengine.HTSUttModel;
import marytts.modules.HTSEngine;
import marytts.unitselection.select.Target;
import marytts.util.data.DoubleDataSource;
import marytts.util.data.audio.AppendableSequenceAudioInputStream;
import marytts.util.data.audio.DDSAudioInputStream;

public class InteractiveHTSEngine extends HTSEngine {

    public boolean synthesizeAudio = true; 
    
    public static boolean returnIncrementalAudioStream = false;
    
    public final List<SynthesisPayload> uttData = new ArrayList<SynthesisPayload>();
    
    @Override
    public MaryData process(MaryData d, List<Target> targetFeaturesList, List<Element> segmentsAndBoundaries, List<Element> tokensAndBoundaries)
    throws Exception
    {

        /** The utterance model, um, is a Vector (or linked list) of Model objects. 
         * It will contain the list of models for current label file. */
        /* Process label file of Mary context features and creates UttModel um */
        HTSUttModel um = processTargetList(targetFeaturesList, segmentsAndBoundaries, MaryAdapter5internal.getDefaultHMMData());
        assert um.getNumModel() == targetFeaturesList.size() : "UttModel size is " + um.getNumModel() + ", but targetFeaturesList size is " + targetFeaturesList.size();
        for (int i = 0; i < um.getNumModel(); i++) {
        	uttData.add(new SynthesisPayload(targetFeaturesList.get(i).getFeatureVector(), um.getUttModel(i), ((HMMVoice)d.getDefaultVoice()).getHMMData()));
        }
        
        MaryData output = new MaryData(outputType(), d.getLocale());
        if (synthesizeAudio) {
            AudioInputStream ais = null;
            /* Process UttModel */
            // Generate sequence of speech parameter vectors, generate parameters out of sequence of pdf's  
            // # non-incremental MaryTTS version:
            /**/ HTSParameterGeneration npdf2par = new HTSParameterGeneration();
            npdf2par.htsMaximumLikelihoodParameterGeneration(um, MaryAdapter5internal.getDefaultHMMData());
            FullPStream pstream = new HTSFullPStream(npdf2par); /**/
            // # incremental pHTS version:
            /* PHTSParameterGeneration pdf2par = MaryAdapter5internal.getNewParamGen(); // new PHTSParameterGeneration(hmmv.getHMMData());
            FullPStream pstream = pdf2par.buildFullPStreamFor(uttHMMs); /**/
	        /* Vocode speech waveform out of sequence of parameters */
	        DoubleDataSource dds = new VocodingAudioStream(pstream, MaryAdapter5internal.getDefaultHMMData(), returnIncrementalAudioStream);
	        float sampleRate = 16000.0F;  //8000,11025,16000,22050,44100
	        int sampleSizeInBits = 16;  //8,16
	        int channels = 1;     //1,2
	        boolean signed = true;    //true,false
	        boolean bigEndian = false;  //true,false
	        AudioFormat af = new AudioFormat(
	              sampleRate,
	              sampleSizeInBits,
	              channels,
	              signed,
	              bigEndian);
	        ais = new DDSAudioInputStream(dds, af);
	        if (d.getAudioFileFormat() != null) {
	            output.setAudioFileFormat(d.getAudioFileFormat());
	            if (d.getAudio() != null) {
	               // This (empty) AppendableSequenceAudioInputStream object allows a 
	               // thread reading the audio data on the other "end" to get to our data as we are producing it.
	                assert d.getAudio() instanceof AppendableSequenceAudioInputStream;
	                output.setAudio(d.getAudio());
	            }
	        }     
	        output.appendAudio(ais);
        }	       
        // set the actualDurations in tokensAndBoundaries
        if(tokensAndBoundaries != null)
            setRealisedProsody(tokensAndBoundaries, um);
        
        return output;
    }

    public List<SynthesisPayload> getUttData() {
		assert uttData != null : "You are calling getUttHMMs without having called my process() method before (Hint: you may think that it was called but the buildpath order might be in your way.)";
		return new ArrayList<SynthesisPayload>(uttData);
    }
    
	public void resetUttHMMstore() {
		uttData.clear();
	}
    
}
@@ -327,16 +327,50 @@
 ryData;%0A
+import marytts.htsengine.HMMData;%0A
 import m
@@ -392,24 +392,24 @@
 e.HMMVoice;%0A
-
 import maryt
@@ -517,16 +517,56 @@
 Engine;%0A
+import marytts.modules.synthesis.Voice;%0A
 import m
@@ -1450,24 +1450,276 @@
 Model um */%0A
+    %09Voice voice = d.getDefaultVoice();%0A    %09assert (voice instanceof HMMVoice) : %22Not an HMM voice: %22 + voice;%0A    %09HMMData hmmData = ((HMMVoice) voice).getHMMData();%0A    %09if (hmmData == null)%0A    %09%09hmmData = MaryAdapter5internal.getDefaultHMMData();%0A
         HTSU
@@ -1796,48 +1796,15 @@
 es, 
-MaryAdapter5internal.getDefaultHMM
+hmm
 Data
-()
 );%0A 
@@ -2135,52 +2135,15 @@
 i), 
-((HMMVoice)d.getDefaultVoice()).getHMM
+hmm
 Data
-()
 ));%0A
@@ -2646,48 +2646,15 @@
 um, 
-MaryAdapter5internal.getDefaultHMM
+hmm
 Data
-()
 );%0A 
@@ -3117,48 +3117,15 @@
 am, 
-MaryAdapter5internal.getDefaultHMM
+hmm
 Data
-()
 , re

use voice as given in MaryXML document, if available