content: package zemberek.morphology.analysis.tr;
  
  import java.util.Arrays;
  import java.util.Collection;
  
  /**
   * Converts a number from text form to digit form for turkish.
   */
  public class TurkishTextToNumberConverter {
  
    /**
     * Converts an array of digit text Strings to a long number.
     * <p>Example:
     * <p>[on,iki] returns 12
     * <p>[bin,on,iki] returns 1012
     * <p>[seksen,iki,milyon,iki] returns 82000002
     *
     * @param words digit string array
     * @return number equivalent of the word array, or -1 if word array is not parseable like
     * [bir,bin] [milyon] [on,bir,iki]
     */
    public long convert(String... words) {
      return convert(Arrays.asList(words));
    }
  
    public long convert(Collection<String> words) {
      Context context = new Context();
      State state = State.START;
      for (String word : words) {
        state = context.acceptTransition(state, new Transition(word));
        if (state == State.ERROR) {
          return -1;
        }
      }
      return context.valueToAdd + context.total;
    }
  
    private static class Context {
  
      private long total;
      private long valueToAdd;
      private Transition previousMil = new Transition("sıfır");
  
      private State acceptTransition(State currentState, Transition transition) {
  
        switch (transition.type) {
  
          case T_ZERO:
            if (currentState == State.START) {
              return total == 0 ? State.END : State.ERROR;
            }
            break;
  
          case T_ONE:
            switch (currentState) {
              case START:
                add(1);
                return State.ST_ONES_1;
              case ST_TENS_1:
                add(1);
                return State.ST_ONES_3;
              case ST_TENS_2:
              case ST_HUNDREDS_1:
                add(1);
                return State.ST_ONES_4;
              case ST_TENS_3:
              case ST_HUNDREDS_2:
              case ST_THOUSAND:
                add(1);
                return State.ST_ONES_5;
            }
            break;
  
          case T_TWO_TO_NINE:
            switch (currentState) {
              case START:
                add(transition.value);
                return State.ST_ONES_2;
              case ST_TENS_1:
                add(transition.value);
                return State.ST_ONES_3;
              case ST_TENS_2:
              case ST_HUNDREDS_1:
                add(transition.value);
                return State.ST_ONES_4;
              case ST_TENS_3:
              case ST_HUNDREDS_2:
                add(transition.value);
                return State.ST_ONES_5;
              case ST_THOUSAND:
                add(transition.value);
                return State.ST_ONES_6;
            }
            break;
  
          case T_TENS:
            switch (currentState) {
              case START:
                add(transition.value);
                return State.ST_TENS_1;
              case ST_HUNDREDS_1:
                add(transition.value);
                return State.ST_TENS_2;
              case ST_HUNDREDS_2:
              case ST_THOUSAND:
                add(transition.value);
                return State.ST_TENS_3;
            }
            break;
  
          case T_HUNDRED:
            switch (currentState) {
              case START:
              case ST_ONES_2:
                mul100();
                return State.ST_HUNDREDS_1;
              case ST_THOUSAND:
              case ST_ONES_6:
                mul100();
                return State.ST_HUNDREDS_2;
            }
            break;
  
          case T_THOUSAND:
            switch (currentState) {
              case START:
              case ST_ONES_2:
              case ST_ONES_3:
              case ST_ONES_4:
              case ST_TENS_1:
              case ST_TENS_2:
              case ST_HUNDREDS_1:
                addToTotal(transition.value);
                return State.ST_THOUSAND;
            }
            break;
  
          case T_MILLION:
          case T_BILLION:
          case T_TRILLION:
          case T_QUADRILLION:
            switch (currentState) {
              case ST_ONES_1:
              case ST_ONES_2:
              case ST_ONES_3:
              case ST_ONES_4:
              case ST_TENS_1:
              case ST_TENS_2:
              case ST_HUNDREDS_1:
                // millions, billions etc behaves the same.
                // here we prevent "billion" comes after a "million"
                // for this, we remember the last big number in previousMil variable..
                if (previousMil.value == 0 || previousMil.value > transition.value) {
                  previousMil = transition;
                  addToTotal(transition.value);
                  return State.START;
                } else {
                  return State.ERROR;
                }
            }
  
        }
        return State.ERROR;
      }
  
      private void add(long val) {
        valueToAdd += val;
      }
  
      private void mul100() {
        if (valueToAdd == 0) {
          valueToAdd = 100;
        } else {
          valueToAdd = valueToAdd * 100;
        }
      }
  
      private void addToTotal(long val) {
        if (valueToAdd == 0) {
          total += val;
        } else {
          total += valueToAdd * val;
        }
        valueToAdd = 0;
      }
    }
  
  
    private static int digitCount(long num) {
      int i = 0;
      do {
        num = num / 10;
        i++;
      } while (num > 0);
      return i;
    }
  
    private enum State {
      START,
      ST_ONES_1, ST_ONES_2, ST_ONES_3, ST_ONES_4, ST_ONES_5, ST_ONES_6,
      ST_TENS_1, ST_TENS_2, ST_TENS_3,
      ST_HUNDREDS_1, ST_HUNDREDS_2,
      ST_THOUSAND,
      END,
      ERROR
    }
  
    private enum TransitionType {
      T_ZERO,
      T_ONE,
      T_TWO_TO_NINE,
      T_TENS,
      T_HUNDRED,
      T_THOUSAND,
      T_MILLION,
      T_BILLION,
      T_TRILLION,
      T_QUADRILLION;
  
      public static TransitionType getTypeByValue(long number) {
        switch (digitCount(number)) {
          case 1:
            if (number == 1) {
              return T_ONE;
            } else if (number == 0) {
              return T_ZERO;
            } else {
              return T_TWO_TO_NINE;
            }
          case 2:
            return T_TENS;
          case 3:
            return T_HUNDRED;
          case 4:
            return T_THOUSAND;
          case 7:
            return T_MILLION;
          case 10:
            return T_BILLION;
          case 13:
            return T_TRILLION;
          case 16:
            return T_QUADRILLION;
          default:
            throw new IllegalArgumentException("cannot create a Transition from value: " + number);
        }
      }
    }
  
    private static class Transition {
  
      final long value;
      final TransitionType type;
  
      Transition(String str) {
        this.value = TurkishNumbers.singleWordNumberValue(str);
        this.type = TransitionType.getTypeByValue(this.value);
      }
  
      public String toString() {
        return "[" + type.name() + ":" + value + "]";
      }
    }
  
  }
  