content: /**
   * Copyright 2007 DFKI GmbH.
   * All Rights Reserved.  Use is subject to license terms.
   * <p/>
   * This file is part of MARY TTS.
   * <p/>
   * MARY TTS is free software: you can redistribute it and/or modify
   * it under the terms of the GNU Lesser General Public License as published by
   * the Free Software Foundation, version 3 of the License.
   * <p/>
   * This program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU Lesser General Public License for more details.
   * <p/>
   * You should have received a copy of the GNU Lesser General Public License
   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
   */
  package marytts.signalproc.adaptation;
  
  import marytts.signalproc.analysis.Label;
  import marytts.signalproc.analysis.Labels;
  import marytts.util.string.StringUtils;
  
  
  /**
   * A wrapper class for representing phonetic context
   *
   * @author Oytun T&uumlrk
   */
  public class Context {
      public static final char leftContextSeparator = '.';
      public static final char rightContextSeparator = ',';
      public static final double LOWEST_CONTEXT_SCORE = 1.0;
      public int numLeftNeighbours;
      public int numRightNeighbours;
      public String allContext;
      public String[] leftContexts;
      public String currentContext;
      public String[] rightContexts;
      private double[] scores;
  
      public Context(Context existing) {
          numLeftNeighbours = existing.numLeftNeighbours;
          numRightNeighbours = existing.numRightNeighbours;
          allContext = existing.allContext;
          setLeftContext(existing.leftContexts);
          currentContext = existing.currentContext;
          setRightContext(existing.rightContexts);
  
          setScores();
          setAllContext();
      }
  
      //Create a full context entry using a concatenated allContext entry
      public Context(String allContextIn) {
          allContext = allContextIn;
          parseAllContext();
      }
  
      public Context(Labels labels, int currentLabelIndex, int totalNeighbours) {
          this(labels, currentLabelIndex, totalNeighbours, totalNeighbours);
      }
  
      // leftContexts[0]                      = labels.items[currentLabelIndex-totalLeftNeighbours].phn
      // leftContexts[1]                      = labels.items[currentLabelIndex-totalLeftNeighbours+1].phn
      // ...
      // leftContexts[totalLeftNeighbours-2]  = labels.items[currentLabelIndex-2].phn
      // leftContexts[totalLeftNeighbours-1]  = labels.items[currentLabelIndex-1].phn
      // currentContext                       = labels.items[currentLabelIndex].phn
      // rightContexts[0]                     = labels.items[currentLabelIndex+1].phn
      // rightContexts[1]                     = labels.items[currentLabelIndex+2].phn
      // ...
      // rightContexts[totalRightNeighbours-2] = labels.items[currentLabelIndex+totalRightNeighbours-1].phn
      // rightContexts[totalRightNeighbours-1] = labels.items[currentLabelIndex+totalRightNeighbours].phn
      // 
      // Note that non-existing context entries are represented by ""
      public Context(Labels labels, int currentLabelIndex, int totalLeftNeighbours, int totalRightNeighbours) {
          leftContexts = null;
          rightContexts = null;
          currentContext = "";
          int i;
  
          if (totalLeftNeighbours > 0) {
              leftContexts = new String[totalLeftNeighbours];
  
              for (i = totalLeftNeighbours; i > 0; i--) {
                  if (labels != null && currentLabelIndex - i >= 0)
                      leftContexts[totalLeftNeighbours - i] = labels.items[currentLabelIndex - i].phn;
                  else
                      leftContexts[totalLeftNeighbours - i] = "";
              }
          }
  
          currentContext = labels.items[currentLabelIndex].phn;
  
          if (totalRightNeighbours > 0) {
              rightContexts = new String[totalRightNeighbours];
  
              for (i = 0; i < totalRightNeighbours; i++) {
                  if (labels != null && currentLabelIndex + i + 1 < labels.items.length)
                      rightContexts[i] = labels.items[currentLabelIndex + i + 1].phn;
                  else
                      rightContexts[i] = "";
              }
          }
  
          setScores();
          setAllContext();
      }
  
      public static void main(String[] args) {
          Label[] items1 = new Label[5];
          Label[] items2 = new Label[5];
          for (int i = 0; i < items1.length; i++) {
              items1[i] = new Label();
              items2[i] = new Label();
          }
          Labels labels1 = new Labels(items1);
          Labels labels2 = new Labels(items2);
  
          labels1.items[0].phn = "A";
          labels1.items[1].phn = "B";
          labels1.items[2].phn = "C";
          labels1.items[3].phn = "D";
          labels1.items[4].phn = "E";
  
          labels2.items[0].phn = "A1";
          labels2.items[1].phn = "B";
          labels2.items[2].phn = "C";
          labels2.items[3].phn = "D1";
          labels2.items[4].phn = "E1";
  
          Context c1 = new Context(labels1, 2, 2);
          Context c2 = new Context(labels2, 2, 2);
  
          System.out.println(String.valueOf(c1.matchScore(c2)));
  
          Context c3 = new Context("t.u.nl,i,n");
          System.out.println(c3.currentContext);
  
          double[] possibleScores = c1.getPossibleScores();
  
          System.out.println("Test completed");
      }
  
      public void setLeftContext(String[] leftContextIn) {
          leftContexts = null;
          if (leftContextIn != null) {
              leftContexts = new String[leftContextIn.length];
              System.arraycopy(leftContextIn, 0, leftContexts, 0, leftContexts.length);
          }
      }
  
      public void setRightContext(String[] rightContextIn) {
          rightContexts = null;
          if (rightContextIn != null) {
              rightContexts = new String[rightContextIn.length];
              System.arraycopy(rightContextIn, 0, rightContexts, 0, rightContexts.length);
          }
      }
  
      public void setScores() {
          int maxContext = 0;
  
          if (leftContexts != null)
              maxContext = leftContexts.length;
  
          if (rightContexts != null)
              maxContext = Math.max(maxContext, rightContexts.length);
  
          scores = new double[maxContext + 1];
  
          double tmpSum = LOWEST_CONTEXT_SCORE;
          for (int i = 0; i < maxContext + 1; i++) {
              scores[i] = tmpSum;
              tmpSum = 2 * tmpSum + 1;
          }
      }
  
      public double[] getPossibleScores() {
          double[] possibleScores = null;
          if (scores != null) {
              possibleScores = new double[2 * (scores.length - 1) + 1];
              double tmpSum = 0.0;
              for (int i = 0; i < scores.length - 2; i++) {
                  possibleScores[2 * i] = tmpSum + scores[i];
                  possibleScores[2 * i + 1] = tmpSum + 2 * scores[i];
                  tmpSum += 2 * scores[i];
              }
              possibleScores[2 * (scores.length - 1)] = tmpSum + scores[scores.length - 1];
          }
  
          return possibleScores;
      }
  
      //allContext = L[0].L[1]...L[N-2].L[N-1].C,R[0],R[1],R[2],...,R[N-1]
      // where L:leftContexts, C:currentContext, R:rightContexts, and "." "," are the left and rightContextSeparators respectively
      public void setAllContext() {
          allContext = "";
  
          int i;
          for (i = 0; i < leftContexts.length; i++)
              allContext += leftContexts[i] + leftContextSeparator;
  
          allContext += currentContext + rightContextSeparator;
  
          for (i = 0; i < rightContexts.length - 1; i++)
              allContext += rightContexts[i] + rightContextSeparator;
  
          allContext += rightContexts[rightContexts.length - 1];
      }
  
      public void parseAllContext() {
          int[] leftInds = StringUtils.find(allContext, leftContextSeparator);
          int i, start;
          if (leftInds != null) {
              leftContexts = new String[leftInds.length];
              start = 0;
              for (i = 0; i < leftInds.length; i++) {
                  leftContexts[i] = allContext.substring(start, leftInds[i]);
                  start = leftInds[i] + 1;
              }
          } else
              leftContexts = null;
  
          int[] rightInds = StringUtils.find(allContext, rightContextSeparator);
          if (rightInds != null) {
              rightContexts = new String[rightInds.length];
              for (i = 0; i < rightInds.length - 1; i++)
                  rightContexts[i] = allContext.substring(rightInds[i] + 1, rightInds[i + 1]);
  
              rightContexts[rightInds.length - 1] = allContext.substring(rightInds[rightInds.length - 1] + 1, allContext.length());
          } else
              rightContexts = null;
  
          if (leftInds != null) {
              if (rightInds != null)
                  currentContext = allContext.substring(leftInds[leftInds.length - 1] + 1, rightInds[0]);
              else
                  currentContext = allContext.substring(leftInds[leftInds.length - 1] + 1, allContext.length());
          } else {
              if (rightInds != null)
                  currentContext = allContext.substring(0, rightInds[0]);
              else
                  currentContext = allContext;
          }
  
          setScores();
      }
  
      public double matchScore(Context context) {
          assert leftContexts.length == context.leftContexts.length;
          assert rightContexts.length == context.rightContexts.length;
  
          int i;
          double score = 0.0;
          if (currentContext.compareTo(context.currentContext) == 0) {
              score += scores[scores.length - 1]; //current context
              for (i = leftContexts.length - 1; i >= 0; i--) {
                  if (leftContexts[i].compareTo(context.leftContexts[i]) == 0)
                      score += scores[i];
                  else
                      break;
              }
  
              for (i = 0; i < rightContexts.length; i++) {
                  if (rightContexts[i].compareTo(context.rightContexts[i]) == 0)
                      score += scores[scores.length - 2 - i];
                  else
                      break;
              }
          }
  
          return score;
      }
  }
  
  