/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package motif;

import hanson.HansonParser;

/**
 *
 * @author smuRf
 */
public class RhythmicMotifDetectorHanson implements MotifDetector{
    private static int MAX_MOTIF_EXTENSION;
    private String type = "";
    private int sizeOffset = 0;
    
    public void setMaxMotifExtension(int mme)
    {
        MAX_MOTIF_EXTENSION = mme;
    }
    
    @Override
    public boolean detect(int intervalStartIndex, Double[] postIntervals, Double[] preIntervals, Double[] postIntervalPattern, Double[] preIntervalPattern, Double[] durations, Double[] durationsPattern) {
        //augmentation - diminution
        sizeOffset = 0;
        boolean equal = true;
        int sameDuration = 0;
        double durationOffset = durations[0] - durationsPattern[0];
        
        for(int k = 0; k < postIntervalPattern.length; k++)
        {
            if((durations[k] - durationsPattern[k]) == durationOffset)
                sameDuration++;
            
            int postIntervalK = (int) (postIntervals[k].doubleValue()/10);
            int postIntervalPatternK = (int) (postIntervalPattern[k].doubleValue()/10);
            if(postIntervalK != postIntervalPatternK || (durations[k] - durationsPattern[k]) != durationOffset)
            {
                equal = false;
                type = "";
                break;
            }
        }
        if(equal && sameDuration != postIntervals.length)
        {
            equal = false;
            type = "";
        }
        else if(equal && sameDuration == postIntervals.length)
        {
            if(durations[0] > durationsPattern[0])
                type = "augmentation";
            else if(durations[0] < durationsPattern[0])
                type = "diminution";
            else
            {
                equal = false;
                type = "";
            }
        }
        
        //duration change single notes
        if(!equal)
        {
            equal = true;
            
            boolean durationMatch = false;
            double patternDuration = 0;
            double matchDuration = 0;
            int i = 0;

            for(double duration:durationsPattern)
                patternDuration += duration;
            
            while(i < postIntervalPattern.length)
            {
                double postIntervalK = postIntervals[i].doubleValue();
                double postIntervalPatternK = postIntervalPattern[i].doubleValue();
                
                String hansonPatternStr = HansonParser.getStringForValue(postIntervalPatternK);
                String hansonIntervalStr = HansonParser.getStringForValue(postIntervalK);

                if(hansonPatternStr.charAt(2) == hansonIntervalStr.charAt(2))
                {
                    int notePatternInterval = (int) (postIntervalPatternK/1000);
                    int notePatternOctave = ((int) ((postIntervalPatternK-(notePatternInterval*1000))/100));
                    int noteInterval = (int) (postIntervalK/1000);
                    int noteOctave = (int) ((postIntervalK-(noteInterval*1000))/100);

                    notePatternInterval = notePatternInterval + notePatternOctave*6;
                    noteInterval = noteInterval + noteOctave*6;
                    
                    if(Math.abs(noteInterval-notePatternInterval) > 3)
                    {
                        equal = false;
                        break;
                    }
                    else
                    {
                        matchDuration += durations[i].doubleValue();
                        
                        if(matchDuration == patternDuration)
                        {
                            durationMatch = true;
                            break;
                        }
                        if(matchDuration > patternDuration)
                        {
                            equal = false;
                            break;
                        }
                    }
                }
                else
                {
                    equal = false;
                    break;
                }
                i++;
            }
            
            if(equal && !durationMatch)
            {
                //longer than pattern                
                int extendIndex = intervalStartIndex + postIntervals.length;
                
                //max four extension notes
                for(int j = 0; j < MAX_MOTIF_EXTENSION; j ++)
                {
                    double extendInterval = PatternMatcher.getInstance().getExtendedPreInterval(extendIndex + j);
                    double extendDuration = PatternMatcher.getInstance().getDurations(extendIndex + j);
                    
                    if(matchDuration+extendDuration > patternDuration || (extendInterval == -3 || extendDuration == -3))
                    {
                        equal = false;
                        type = "";
                        break;
                    }
                    else if(matchDuration+extendDuration < patternDuration)
                    {
                        matchDuration += extendDuration;
                        
                        if(j == (MAX_MOTIF_EXTENSION-1) && matchDuration != patternDuration)
                        {
                            type = "";
                            equal = false;
                        }
                    }
                    else if(matchDuration+extendDuration == patternDuration)
                    {
                        int notePatternInterval = (int) (preIntervalPattern[preIntervalPattern.length-1]/1000);
                        int notePatternOctave = ((int) ((preIntervalPattern[preIntervalPattern.length-1]-(notePatternInterval*1000))/100));
                        int noteInterval = (int) (extendInterval/1000);
                        int noteOctave = (int) ((extendInterval-(noteInterval*1000))/100);

                        notePatternInterval = notePatternInterval + notePatternOctave*6;
                        noteInterval = noteInterval + noteOctave*6;
                        
                        if(Math.abs(noteInterval-notePatternInterval) > 2)
                        {
                            equal = false;
                            type = "";
                            break;
                        }
                        else
                        {
                            type = "match longer";
                            sizeOffset = j + 1;
                            break;
                        }
                    }
                }
                
            }
            else if(equal && durationMatch && i != postIntervalPattern.length-1)
            {
                //shorter than pattern
                sizeOffset = i - postIntervalPattern.length + 1;
                type = "match shorter";
            }
            else if(equal && durationMatch && i == postIntervalPattern.length-1)
            {
                equal = false;
                type = "";
            }
        }
        
        return equal;
    }
    
    public int getSizeOffset()
    {
        return sizeOffset;
    }

    @Override
    public String getType() {
        return type;
    }
    
    
}
