/**
 * *****************************************************************************
 * Copyright C 2015, The Pistoia Alliance
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *****************************************************************************
 */
package org.helm.notation2.parser.notation.polymer;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.helm.notation2.parser.exceptionparser.HELM1ConverterException;
import org.helm.notation2.parser.exceptionparser.NotationException;
import org.helm.notation2.parser.notation.ValidationMethod;
import org.jdom2.JDOMException;

import com.fasterxml.jackson.annotation.JsonIgnore;

/**
 * MonomerNotationGroup
 *
 * @author hecht
 */

public abstract class MonomerNotationGroup extends MonomerNotation {
  @JsonIgnore
  public List<MonomerNotationGroupElement> elements = new ArrayList<MonomerNotationGroupElement>();

  /**
   * Constructs with the given string
   *
   * @param str Monomer in string format
   * @param type polymer type of monomer
   */
  public MonomerNotationGroup(String str, String type) {
    super(str, type);
  }

  /**
   * method to add a single element to the group
   *
   * @param str Monomer
   * @param type type of current polymer
   * @param one value of the monomer
   * @param two value of the monomer
   * @param interval is the value on interval
   * @param isDefault if the value is the default one
   * @throws NotationException if notation is not valid
   */
  public void addElement(String str, String type, double one, double two, boolean interval, boolean isDefault) throws NotationException{
    this.elements.add(ValidationMethod.decideWhichMonomerNotationInGroup(str, type, one, two, interval, isDefault));

  }

  /**
   * method to get the current group element
   *
   * @return MonomerNotationGroupElement
   */
  @JsonIgnore
  public MonomerNotationGroupElement getCurrentElement() {
    return this.elements.get(this.elements.size() - 1);
  }

  /**
   * method to get a list of all group elements
   *
   * @return List of all group elements
   */
  public List<MonomerNotationGroupElement> getListOfElements() {
    return this.elements;
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public String toString() {
    if (isAnnotationTrue()) {
      return "Grouping section:\n " + elements.toString() + "\nCount: " + count + "\nAnnotation: " + annotation;
    } else {
      return "Grouping section:\n " + elements.toString() + "\nCount: " + count;
    }
  }

  @Override
  public String toHELM() throws HELM1ConverterException {
    throw new HELM1ConverterException("Can't be downcasted to HELM1-Format due to a group element");
  }

}


/**
 * *****************************************************************************
 * Copyright C 2015, The Pistoia Alliance
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *****************************************************************************
 */
package org.helm.notation2.parser.connectionsection;

import org.helm.notation2.parser.State;
import org.helm.notation2.parser.StateMachineParser;
import org.helm.notation2.parser.exceptionparser.ConnectionSectionException;
import org.helm.notation2.parser.groupingsection.GroupingParser;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * BetweenInlineConnectionParser class to represent the transition state between
 * the inline annotation and all possible states in the connection parser
 *
 * @author hecht
 */
public class BetweenInlineConnectionParser implements State {

  private StateMachineParser _parser;

  private static final Logger LOG = LoggerFactory.getLogger(BetweenInlineConnectionParser.class);

  /**
   * Constructs with the state machine parser
   *
   * @param pParser current parser
   */
  public BetweenInlineConnectionParser(StateMachineParser pParser) {
    _parser = pParser;
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public void doAction(char cha) throws ConnectionSectionException {
    /* new connection is starting */
    if (cha == '|') {
      LOG.info("A new connection is starting:");
      _parser.setState(new ConnectionsParser(_parser));
    } /* grouping section is starting */ else if (cha == '$') {
      LOG.info("Transition to group section");
      LOG.info("Group section is starting:");
      _parser.setState(new GroupingParser(_parser));
    } /* invalid character */ else {
      LOG.error("Invalid character after inline annotation in connection section: " + cha);
      throw new ConnectionSectionException("Invalid character after inline annotation in connection section: " + cha);
    }

  }

}


/**
 * *****************************************************************************
 * Copyright C 2015, The Pistoia Alliance
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *****************************************************************************
 */
package org.helm.notation2.parser.simplepolymerssection;

import org.helm.notation2.parser.State;
import org.helm.notation2.parser.StateMachineParser;
import org.helm.notation2.parser.exceptionparser.SimplePolymerSectionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * RepeatingMonomerParser class to parse the repeating information
 *
 * @author hecht
 */
public class RepeatingMonomerParser implements State {

  private StateMachineParser _parser;

  private static final Logger LOG = LoggerFactory.getLogger(RepeatingMonomerParser.class);

  private String repeating = "";

  /**
   * Constructs with the state machine parser
   *
   * @param pParser StateMachineParser
   */
  public RepeatingMonomerParser(StateMachineParser pParser) {
    _parser = pParser;
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public void doAction(char cha) throws SimplePolymerSectionException {

    /* repeating information is finished */
    if (cha == '\'') {
      if (_parser.checkRepeating(repeating)) {
        String[] range = repeating.split("-");
        int first = Integer.parseInt(range[0]);
        if (range.length > 1) {
          int second = Integer.parseInt(range[1]);
          /* range is wrong */
          if (second - first <= 0) {
            LOG.error("Information about repeating is wrong: " + repeating);
            throw new SimplePolymerSectionException("Information about repeating is wrong: " + repeating);
          } else {
            LOG.info("Monomer unit is repeated:");
            _parser.notationContainer.getCurrentPolymer().getPolymerElements().getCurrentMonomerNotation().setCount(repeating);
            _parser.setState(new BetweenMonomerParser(_parser));
          }

        } else {
          LOG.info("Monomer unit is repeated:");
          _parser.notationContainer.getCurrentPolymer().getPolymerElements().getCurrentMonomerNotation().setCount(repeating);
          _parser.setState(new BetweenMonomerParser(_parser));
        }

      } else {
        LOG.error("Information about repeating is wrong: " + repeating);
        throw new SimplePolymerSectionException("Information about repeating is wrong: " + repeating);
      }
    } /* add characters to repeating information */ else {
      repeating += cha;
    }
  }

}


/**
 * *****************************************************************************
 * Copyright C 2015, The Pistoia Alliance
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *****************************************************************************
 */
package org.helm.notation2.parser;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;

import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.DefaultParser;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.helm.notation2.parser.exceptionparser.ExceptionState;
import org.jdom2.JDOMException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * code StartHELM2Parser main class to run a single HELM2Parser from the command
 * line
 *
 * @author hecht
 */
public final class StartHELM2Parser {

  /** The Logger for this class */
  private static final Logger LOG = LoggerFactory.getLogger(StartHELM2Parser.class);

  /**
   * Default constructor
   */
  private StartHELM2Parser() {

  }

  /**
   * main method to run a single HELM2Parser from the command line
   *
   * @param args console parameters
   * @throws ParseException if parsing the command lines produces an error
   * @throws ExceptionState an exception in a state during parsing occurs, helm notation is not valid
   * @throws IOException if file can not be read
   */
  public static void main(String[] args) throws ParseException,
      ExceptionState, IOException {
    /* options for the program */
    Options options = new Options();
    /* add helm string */
    options.addOption("inputHELM", true, "HELM1 or HELM2 string in a file");

    /* add output option */
    options.addOption("output", true, "output can be in JSON- or HELM2-format");

    /* add translate option */
    options.addOption("translate", false, "translate HELM1 to HELM2");

    CommandLineParser parameter = new DefaultParser();
    try {

      CommandLine cmd = parameter.parse(options, args);

      String filename = cmd.getOptionValue("inputHELM");

      ParserHELM2 parser = new ParserHELM2();

      FileReader in = new FileReader(filename);

      BufferedReader br = new BufferedReader(in);

      String line;
      String helm;
      try {
        while ((line = br.readLine()) != null) {
          helm = line;
          /* HELM1 notation has to be translated into HELM2 */
          if (cmd.hasOption("translate")) {

            ConverterHELM1ToHELM2 converter = new ConverterHELM1ToHELM2();
            helm = converter.doConvert(helm);
            LOG.info("HELM1 is translated to HELM2");
          }

          parser.parse(helm);

          /* There are two different output options */
          String output = "";
          if (cmd.getOptionValue("output").equals("HELM2")) {
            output = parser.getHELM2Notation().toHELM2();
          } else if (cmd.getOptionValue("output").equals("JSON")) {

            output = parser.getJSON();
          }
          System.out.println(output);
        }
      } finally {
        br.close();
      }
    } catch (NullPointerException e) {
      System.out.println("Please call the program with the following arguments: "
          + "\n"
          + "-inputHELM  <"
          + options.getOption("inputHELM").getDescription()
          + ">\n"
          + "-output <"
          + options.getOption("output").getDescription()
          + ">\n-translate(optional) <"
          + options.getOption("translate").getDescription()
          + ">");
    } catch (ParseException exp) {
      System.out.println("Unexpected exception: " + exp.getMessage());
    }

  }

}


/**
 * *****************************************************************************
 * Copyright C 2015, The Pistoia Alliance
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *****************************************************************************
 */
package org.helm.notation2.parser.simplepolymerssection;

import java.io.IOException;

import org.helm.notation2.parser.InlineAnnotationsParser;
import org.helm.notation2.parser.State;
import org.helm.notation2.parser.StateMachineParser;
import org.helm.notation2.parser.exceptionparser.NotationException;
import org.helm.notation2.parser.exceptionparser.SimplePolymerSectionException;
import org.jdom2.JDOMException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * SimplePolymersNotationParser class to parse the notation of an simple polymer
 *
 * @author hecht
 */
public class SimplePolymersNotationParser implements State {
  private StateMachineParser _parser;

  private String monomer = "";

  private int bracketCounterOpen = 0;

  private int bracketCounterClose = 0;

  private int parenthesisCounterOpen = 0;

  private int parenthesisCounterClose = 0;

  private static final Logger LOG = LoggerFactory.getLogger(SimplePolymersNotationParser.class);

  /**
   * Constructs with the state machine
   *
   * @param pParser StateMachineParser
   */
  public SimplePolymersNotationParser(StateMachineParser pParser) {
    _parser = pParser;

  }

  /**
   * {@inheritDoc}
   * @throws SimplePolymerSectionException is simple polymer section is not valid
   * @throws NotationException if notation is not valid
   */
  @Override
  public void doAction(char cha) throws SimplePolymerSectionException, NotationException{
    /* simple polymer notation is finished; can also be empty */
    if (cha == '}' && checkBracketsParenthesis()) {
      // initialize object - normal monomer type
      if (!(monomer.equals(""))) {
        LOG.info("Monomer unit is read:");
        _parser.notationContainer.getCurrentPolymer().getPolymerElements().addMonomerNotation(monomer);
        _parser.setState(new BetweenParser(_parser));
      } else {
        throw new SimplePolymerSectionException("Monomer unit is missing: ");
      }
    } else if (cha == '.' && checkBracketsParenthesis()) {
      /*
       * a new monomer unit is starting. This is only valid for peptide and rna
       * not for chem and blob
       */
      if (monomer != "") {
        if (_parser.isPeptideOrRna()) {
          LOG.info("Monomer unit is read: " + monomer);
          LOG.info("New monomer unit is starting:");
          _parser.notationContainer.getCurrentPolymer().getPolymerElements().addMonomerNotation(monomer);
          _parser.setState(new SimplePolymersNotationParser(_parser));
        } else {
          LOG.error("Only one monomer unit is allowed: " + monomer);
          throw new SimplePolymerSectionException("Only one monomer unit is allowed: " + monomer);
        }
      } else {
        LOG.error("Monomer unit is missing: " + monomer);
        throw new SimplePolymerSectionException("Monomer unit is missing: " + monomer);
      }

    } /* an additional annotation is given */ else if (cha == '"' && checkBracketsParenthesis()) {
      if (monomer != "") {
        LOG.info("Monomer unit is read: " + monomer);
        LOG.info("Annotation for monomer unit is starting:");
        _parser.notationContainer.getCurrentPolymer().getPolymerElements().addMonomerNotation(monomer);
        _parser.setState(new InlineAnnotationsParser(_parser, 11));
      } else {
        LOG.error("Monomer unit is missing:");
        throw new SimplePolymerSectionException("Monomer unit is missing:");
      }
    } else if (cha == '\'' && checkBracketsParenthesis()) {
      /*
       * the monomer unit is being repeated. This is only valid for peptide and
       * rna not for chem and blob
       */
      if (monomer != "") {
        if (_parser.isPeptideOrRna()) {
          LOG.info("Monomer unit is read: " + monomer);
          _parser.notationContainer.getCurrentPolymer().getPolymerElements().addMonomerNotation(monomer);
          _parser.setState(new RepeatingMonomerParser(_parser));
        } else {
          LOG.error("Monomer unit shall be not repeated: ");
          throw new SimplePolymerSectionException("Monomer unit shall be not repeated: ");
        }
      } else {
        LOG.error("Monomer unit is missing");
        throw new SimplePolymerSectionException("Monomer unit is missing");
      }

    } /* check all brackets */ else if (cha == '[' || cha == ']' || cha == '(' || cha == ')') {
      monomer += cha;
      if (cha == '[') {
        bracketCounterOpen += 1;
      } else if (cha == ']') {
        bracketCounterClose += 1;
      } else if (cha == '(') {
        parenthesisCounterOpen += 1;

      } else {
        parenthesisCounterClose += 1;

      }
    } /* add characters */ else {
      monomer += cha;
    }

  }

  /**
   * method to check if all open brackets are closed
   *
   * @return true if all open brackets are close, false otherwise
   */
  private boolean checkBracketsParenthesis() {
    if (bracketCounterOpen == bracketCounterClose && parenthesisCounterOpen == parenthesisCounterClose) {
      return true;
    }
    return false;
  }

}


/**
 * *****************************************************************************
 * Copyright C 2015, The Pistoia Alliance
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *****************************************************************************
 */
package org.helm.notation2.parser;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.helm.notation2.parser.exceptionparser.ExceptionState;
import org.helm.notation2.parser.exceptionparser.SimplePolymerSectionException;
import org.helm.notation2.parser.notation.HELM2Notation;
import org.helm.notation2.parser.simplepolymerssection.SimplePolymersParser;
import org.jdom2.JDOMException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.fasterxml.jackson.databind.ObjectMapper;

/**
 * StateMachineParser class to represent the state machine to parse the HELM2
 * string
 *
 * @author hecht
 */
public class StateMachineParser implements State {

  private State state;

  private List<String> polymerElements = new ArrayList<String>(); // saves all
                                                                  // simple
                                                                  // polymer in
                                                                  // a
                                                                  // list

  public HELM2Notation notationContainer = new HELM2Notation();

  private static final Logger LOG = LoggerFactory.getLogger(StateMachineParser.class);

  /**
   * Constructs the state machine with the start state
   */
  public StateMachineParser() {
    setState(new SimplePolymersParser(this));
  }

  /**
   * method to set the current state
   *
   * @param state current state
   */
  public void setState(State state) {
    this.state = state;
  }

  /**
   * method to get the current state
   *
   * @return state
   */
  public State getState() {
    return this.state;
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public void doAction(char car) throws ExceptionState{
    this.state.doAction(car);

  }

  /**
   * method to validate the polymer id in the simple polymer section the id can
   * be peptide, rna, chem or blob
   *
   * @param polymerId ID of a polymer
   * @return true if the ID is valid, false otherwise
   */
  public boolean checkPolymerId(String polymerId) {
    LOG.debug("Validation of polymerID: " + polymerId);
    String pattern = "PEPTIDE[1-9][0-9]*|RNA[1-9][0-9]*|CHEM[1-9][0-9]*|BLOB[1-9][0-9]*";

    Pattern p = Pattern.compile(pattern, Pattern.CASE_INSENSITIVE);
    Matcher m = p.matcher(polymerId);
    if (m.matches()) {
      LOG.debug("PolymerID is valid: " + polymerId);
      return true;
    }

    LOG.debug("PolymerID is not valid: " + polymerId);
    return false;
  }

  /**
   * method to validate the polymer id in the connection section the id can be
   * peptide, rna, chem or blob the ratio + range was also included, the
   * ambiguity is also proven
   *
   * @param polymerId ID of a polymer
   * @return true if the ID is valid, false otherwise
   */
  public boolean checkPolymeridConnection(String polymerId) {
    LOG.debug("Validation of polymerID in the connection section:");
    String ratio = "(:[1-9][0-9]*(\\.[0-9]+)?)?";
    String id = "(PEPTIDE[1-9][0-9]*|RNA[1-9][0-9]*|CHEM[1-9][0-9]*|BLOB[1-9][0-9]*|G[1-9][0-9]*)";
    String pattern = "(\\(" + id + ratio + "(," + id + ratio + ")+\\)" + ratio + "|" + id + ratio + ")";
    Pattern p = Pattern.compile(pattern,Pattern.CASE_INSENSITIVE);
    Matcher m  = p.matcher(polymerId);
    if (m.matches()) {
      LOG.debug("PolymerID in the connection section is valid:");
      return true;
    }

    LOG.debug("PolymerID in the connection section is not valid: " + polymerId);
    return false;
  }

  /**
   * method to validate the details about the connections; hydrogen bonds are
   * here included
   *
   * @param d connection details
   * @return true if the connection details are valid, false otherwise
   */
  public boolean checkDetailsConnections(String d) {
    LOG.debug("Validation of connection's details:");
    String group = "\\((\\D|\\d)((,|\\+)(\\D|\\d))+\\)";
    String partOne = "([1-9][0-9]*|\\D|\\?|" + group + ")";
    String partTwo = "(R[1-9][0-9]*+|\\?)";
    String element = partOne + ":" + partTwo;
    String patternConnection = element + "-" + element;
    String hydrogenBondPartner = partOne + ":pair";
    String hydrogenBondPattern = hydrogenBondPartner + "-" + hydrogenBondPartner;
    Pattern pConnection = Pattern.compile(patternConnection , Pattern.CASE_INSENSITIVE);
    Matcher mConnection = pConnection.matcher(d);
    Pattern pHydrogen = Pattern.compile(hydrogenBondPattern, Pattern.CASE_INSENSITIVE);
    Matcher mHydrogen = pHydrogen.matcher(d);
    if (mConnection.matches() || mHydrogen.matches()) {
      LOG.debug("Connection's details are valid:");
      return true;
    }
    LOG.debug("Connection's details are not valid: " + d);
    return false;
  }

  /**
   * method to validate the group id
   *
   * @param d ID of a group
   * @return true if the connection details are valid, false otherwise
   */
  public boolean checkGroupId(String d) {
	  Pattern p = Pattern.compile("G[1-9][0-9]*", Pattern.CASE_INSENSITIVE);
	  Matcher m = p.matcher(d);
    LOG.debug("Validation of groupID:");
    if (m.matches()) {
      LOG.debug("GroupID is valid:");
      return true;
    }
    LOG.debug("GroupID is not valid:");
    return false;
  }

  /**
   * method to validate the details about the group information; this part can
   * be separated after + to get the id for each single group element : to get
   * the ratio for each single group element
   *
   * @param d group information
   * @return true if the group information is valid, false otherwise
   */
  public boolean checkDetailsGroup(String d) {
    LOG.debug("Validation of group's details:");
    String id = "(PEPTIDE[1-9][0-9]*+|RNA[1-9][0-9]*|CHEM[1-9][0-9]*|BLOB[1-9][0-9]*|G[1-9][0-9]*)";
    String number = "[1-9][0-9]*(\\.[0-9]+)?";
    String ratio = number + "(-" + number + ")?";
    String pattern = id + "(:" + ratio + ")?((\\+|,)" + id + "(:" + ratio + ")?)+";

    Pattern p = Pattern.compile(pattern, Pattern.CASE_INSENSITIVE);
    Matcher m = p.matcher(d);
    if (m.matches()) {
      LOG.debug("Group's details are valid:");
      return true;
    }
    LOG.debug("Group's details are not valid: " + d);
    return false;
  }

  /**
   * method to validate the repeating section it can be a single number or a
   * range
   *
   * @param str repeating information
   * @return true if the information is valid, false otherwise
   */
  public boolean checkRepeating(String str) {
    String pattern = "\\d+|\\d+-\\d+";
    if (str.matches(pattern)) {
      return true;
    }
    return false;
  }

  /**
   * method to add the polymer id to the list
   *
   * @param str polymerID
   */
  public void addPolymer(String str) {
    polymerElements.add(str.toUpperCase());
  }

  /**
   * method to check if the list containing all polymer elements is empty
   *
   * @return true of no polymer id is found, false otherwise
   */
  public boolean isEmpty() {
    if (polymerElements.isEmpty()) {
      return true;
    }
    return false;
  }

  /**
   * method to check if the last added polymer element is a peptide or a rna
   *
   * @return true, if the last added polymer is a peptide or a rna, false
   *         otherwise
   * @throws SimplePolymerSectionException if list of polymers is null
   */
  public boolean isPeptideOrRna() throws SimplePolymerSectionException {
    if (polymerElements.size() >= 1) {
      if (polymerElements.get(polymerElements.size() - 1).matches("(PEPTIDE[1-9][0-9]*+|RNA[1-9][0-9]*)")) {
        return true;
      }
      return false;
    } else {
      throw new SimplePolymerSectionException("No Polymer Id is found");
    }
  }

  /**
   * method to generate a JSON-Object from the NotationContainer
   *
   * @return NotationContainer in JSON-Format
   */
  protected String toJSON() {
    ObjectMapper mapper = new ObjectMapper();

    try {
      String jsonINString = mapper.writeValueAsString(notationContainer);
      jsonINString = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(notationContainer);

      return jsonINString;
    } catch (Exception e) {
      e.printStackTrace();
    }
    return null;
  }

}


/**
 * *****************************************************************************
 * Copyright C 2015, The Pistoia Alliance
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *****************************************************************************
 */
package org.helm.notation2.parser;

import org.helm.notation2.parser.connectionsection.BetweenInlineConnectionParser;
import org.helm.notation2.parser.notation.connection.ConnectionNotation;
import org.helm.notation2.parser.notation.polymer.PolymerNotation;
import org.helm.notation2.parser.simplepolymerssection.BetweenInlineMonomerParser;
import org.helm.notation2.parser.simplepolymerssection.BetweenParser;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * InlineAnnotationsParser class to read/catch the inline annotation
 *
 * @author hecht
 */
public class InlineAnnotationsParser implements State {

  private StateMachineParser _parser;

  private int sectionCounter; // information about the next state after the
                              // annotation

  private static final Logger LOG = LoggerFactory.getLogger(InlineAnnotationsParser.class);

  private String comment = "";

  /**
   * Constructor with the state machine parser, an information about the next
   * state
   *
   * @param pParser StateMachineParser
   * @param counter information about the following state
   */
  public InlineAnnotationsParser(StateMachineParser pParser, int counter) {
    this._parser = pParser;
    this.sectionCounter = counter;
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public void doAction(char cha) {

    if (cha == '\"') {

      /* annotation for first section:simple polymer section */
      if (sectionCounter == 1) {
        LOG.info("Add annotation to simple polymer:");
        PolymerNotation current = _parser.notationContainer.getCurrentPolymer();
        _parser.notationContainer.changeLastPolymerNotation(new PolymerNotation(current.getPolymerID(),
            current.getPolymerElements(), comment));
        _parser.setState(new BetweenParser(_parser));
      } /* annotation for second section:connection section */ else if (sectionCounter == 2) {
        LOG.info("Add annotation to connection section:");
        ConnectionNotation current = _parser.notationContainer.getCurrentConnection();
        _parser.notationContainer.changeConnectionNotation(new ConnectionNotation(current.getSourceId(),
            current.getTargetId(), current.getSourceUnit(), current.getTargetUnit(), current.getrGroupSource(),
            current.getrGroupTarget(), comment));
        _parser.setState(new BetweenInlineConnectionParser(_parser));
      } /* annotation for a single monomer in the first section */ else if (sectionCounter == 11) {
        LOG.info("Add annotation to a single monomer:");
        _parser.notationContainer.getCurrentPolymer().getPolymerElements().getCurrentMonomerNotation().setAnnotation(comment);
        _parser.setState(new BetweenInlineMonomerParser(_parser));
      }

    } else {
      comment += (cha);
    }
  }

}


/**
 * *****************************************************************************
 * Copyright C 2015, The Pistoia Alliance
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *****************************************************************************
 */
package org.helm.notation2.parser.simplepolymerssection;

import org.helm.notation2.parser.InlineAnnotationsParser;
import org.helm.notation2.parser.State;
import org.helm.notation2.parser.StateMachineParser;
import org.helm.notation2.parser.exceptionparser.SimplePolymerSectionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * BetweenMonomerParser class to represent the interstate between a repeating
 * monomer section and all possible states
 *
 * @author hecht
 */
public class BetweenMonomerParser implements State {

  private StateMachineParser _parser;

  private static final Logger LOG = LoggerFactory.getLogger(BetweenMonomerParser.class);

  /**
   * Constructs with the state machine parser
   *
   * @param pParser StateMacchineParser
   */
  public BetweenMonomerParser(StateMachineParser pParser) {
    _parser = pParser;
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public void doAction(char cha) throws SimplePolymerSectionException {
    /* a new monomer section starts */
    if (cha == '.') {
      LOG.info("new monomer unit is starting:");
      _parser.setState(new SimplePolymersNotationParser(_parser));
    } /* polymer is finished */ else if (cha == '}') {
      LOG.info("simple polymer is read:");
      _parser.setState(new BetweenParser(_parser));
    } /* inline annotation */ else if (cha == '"') {
      LOG.info("annotation for simple polymer is starting:");
      _parser.setState(new InlineAnnotationsParser(_parser, 11));
    } else {
      LOG.error("Error in the simple polymers notation section:");
      throw new SimplePolymerSectionException("Error in the simple polymers notation section:");
    }
  }

}


/**
 * *****************************************************************************
 * Copyright C 2015, The Pistoia Alliance
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *****************************************************************************
 */
package org.helm.notation2.parser.notation.polymer;

import java.io.IOException;
import java.text.DecimalFormat;

import org.helm.notation2.parser.exceptionparser.NotationException;
import org.jdom2.JDOMException;

/**
 * MonomerNotationGroupOr class to represent an or group
 *
 * @author hecht
 */
public class MonomerNotationGroupOr extends MonomerNotationGroup {

  /**
   * Constructs with the given String an Or group
   *
   * @param str details about the group
   * @param type type of the current polymer
   * @throws NotationException if notation is not valid
   */
  public MonomerNotationGroupOr(String str, String type) throws NotationException {
    super(str, type);
    /* Or elements are separated by , */
    String[] parts = str.split(",");
    boolean interval = false;
    for (int i = 0; i < parts.length; ++i) {
      /* Ratio can be defined -> default is 1 */
      String[] item = parts[i].split(":");
      double probability = 1;
      double probability2 = 1;
      boolean isDefault = true;
      interval = false;
      if (item.length > 1) {
        /* an interval can be there or not */
        if (item[1].split("-").length > 1) {
          interval = true;
          probability = Float.parseFloat(item[1].split("-")[0]);
          probability2 = Float.parseFloat(item[1].split("-")[1]);
          isDefault = false;
        } else {
          if ((Math.abs(Float.parseFloat(item[1]) - 1.0) > 0.00000001)) {
            probability = Float.parseFloat(item[1]);
            isDefault = false;
          }
          /* unknown ratio */
          if (item[1].contains("?")) {
            probability = -1;
            isDefault = false;
          }

        }
      }

      /* Add element to the list */
      addElement(item[0], type, probability, probability2, interval, isDefault);
    }
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public String toHELM2() {
    StringBuilder notation = new StringBuilder();
    DecimalFormat d = new DecimalFormat("#.##");
    notation.append("(");
    for (int i = 0; i < elements.size(); i++) {
      String text = elements.get(i).getMonomerNotation().getUnit();
      if (!(elements.get(i).isDefaultValue())) {
        String value = d.format(elements.get(i).getValue().get(0)).replace(',', '.');
        if (elements.get(i).isInterval()) {
          value += "-" + d.format(elements.get(i).getValue().get(1)).replace(',', '.');
        }

        if (value.equals("-1")) {
          value = "?";
        }

        text += ":" + value;
      }
      notation.append(text + ",");
    }

    notation.setLength(notation.length() - 1);
    notation.append(")");

    if (!(isDefault)) {
      notation.append("'" + count + "'");
    }

    if (isAnnotationHere) {
      notation.append("\"" + annotation + "\"");
    }

    return notation.toString();

  }

}


/**
 * *****************************************************************************
 * Copyright C 2015, The Pistoia Alliance
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *****************************************************************************
 */
package org.helm.notation2.parser.notation;

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

import org.helm.notation2.parser.notation.annotation.AnnotationNotation;
import org.helm.notation2.parser.notation.connection.ConnectionNotation;
import org.helm.notation2.parser.notation.grouping.GroupingNotation;
import org.helm.notation2.parser.notation.polymer.PolymerNotation;

import com.fasterxml.jackson.annotation.JsonIgnore;

/**
 * HELM2Notation this class contains all notation objects for HELM2
 *
 * @author hecht
 *
 */
public class HELM2Notation {

  private List<PolymerNotation> listOfPolymers = new ArrayList<PolymerNotation>();

  private List<ConnectionNotation> listOfConnections = new ArrayList<ConnectionNotation>();

  private List<GroupingNotation> listOfGroupings = new ArrayList<GroupingNotation>();

  private List<AnnotationNotation> annotationSection = new ArrayList<AnnotationNotation>();

  /**
   * method to add the notation of a simple polymer type
   *
   * @param pol new polymer notation
   */
  @JsonIgnore
  public void addPolymer(PolymerNotation pol) {
    listOfPolymers.add(pol);
  }

  /**
   * method to get the current simple polymer type
   *
   * @return current polymer notation
   */
  @JsonIgnore
  public PolymerNotation getCurrentPolymer() {
    return listOfPolymers.get(listOfPolymers.size() - 1);
  }

  /**
   * method to get all simple polymer types
   *
   * @return all simple polymer types in a List
   */
  public List<PolymerNotation> getListOfPolymers() {
    return listOfPolymers;
  }

  /**
   * method to get the simple polymer type
   * @param string id of polymer
   * @return PolymerNotation with the given id
   */
  public PolymerNotation getSimplePolymer(String string) {
    for (PolymerNotation polymer : listOfPolymers) {
      if (polymer.getPolymerID().getId().equals(string)) {
        return polymer;
      }
    }
    return null;
  }

  /**
   * method to change the last polymer notation
   *
   * @param not New PolymerNotation
   */
  public void changeLastPolymerNotation(PolymerNotation not) {
    listOfPolymers.set(listOfPolymers.size() - 1, not);
  }

  /**
   * method to add a connection
   *
   * @param con new connection notation
   */
  public void addConnection(ConnectionNotation con) {

    listOfConnections.add(con);
  }

  /**
   * method to get the current connection
   *
   * @return the current connection notation
   */
  @JsonIgnore
  public ConnectionNotation getCurrentConnection() {
    return listOfConnections.get(listOfConnections.size() - 1);
  }

  /**
   * method to change the last connection notation
   *
   * @param not new connection notation
   */
  public void changeConnectionNotation(ConnectionNotation not) {
    listOfConnections.set(listOfConnections.size() - 1, not);
  }

  /**
   * method to get a list of all connections
   *
   * @return all connection notations in a list
   */
  public List<ConnectionNotation> getListOfConnections() {
    return listOfConnections;
  }

  /**
   * method to add a grouping notation
   *
   * @param not new grouping notation
   */
  public void addGrouping(GroupingNotation not) {
    listOfGroupings.add(not);
  }

  /**
   * method to get the current grouping notation
   *
   * @return GroupingNotation
   */
  @JsonIgnore
  public GroupingNotation getCurrentGroupingNotation() {
    if (listOfGroupings.size() == 0) {
      return null;
    }
    return listOfGroupings.get(listOfGroupings.size() - 1);
  }

  /**
   * method to get all grouping notations
   *
   * @return all grouping notations in a list
   */
  public List<GroupingNotation> getListOfGroupings() {
    return listOfGroupings;
  }

  /**
   * method to change the current grouping notation
   *
   * @param not new grouping notation
   */
  public void changeLastGroupingNotation(GroupingNotation not) {
    listOfGroupings.set(listOfGroupings.size() - 1, not);
  }

  /**
   * method to set the annotation
   *
   * @param anno new annotation
   */
  public void addAnnotation(AnnotationNotation anno) {
    annotationSection.add(anno);
  }

  /**
   * method to get the annotation
   *
   * @return annotation
   */
  public List<AnnotationNotation> getListOfAnnotations() {
    return annotationSection;
  }

  @JsonIgnore
  public AnnotationNotation getCurrentAnnotation() {
    return annotationSection.get(annotationSection.size() - 1);
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public String toString() {
    String output = "PolymerSection: " + listOfPolymers.toString() + "\n";
    if (!(listOfConnections.isEmpty())) {
      output += "ConnectionSection: " + listOfConnections.toString() + "\n";
    }

    if (!(listOfGroupings.isEmpty())) {
      output += "GroupingSection: " + listOfGroupings.toString() + "\n";
    }

    if (!(annotationSection.isEmpty())) {
      output += "AnnotationSection: " + annotationSection.toString() + "\n";
    }

    return output;
  }

  /**
   * method to generate for all sections a HELM2 string
   *
   * @return HELM2
   */
  public String toHELM2() {
    String output = "";
    /* first section: simple polymer section */
    output += polymerToHELM2() + "$";

    /* second section: connection section */
    output += connectionToHELM2() + "$";

    /* third section: grouping section */
    output += groupingToHELM2() + "$";

    /* fourth section: annotation section */
    output += annotationToHELM2() + "$";

    /* add version number */
    output += "V2.0";

    return output;
  }

  /**
   * method to generate a valid HELM2 string for the first section
   *
   * @return valid HELM2 string
   */
  public String polymerToHELM2() {
    StringBuilder notation = new StringBuilder();
    for (int i = 0; i < listOfPolymers.size(); i++) {
      if (listOfPolymers.get(i).isAnnotationHere()) {
        notation.append(listOfPolymers.get(i).getPolymerID() + "{" + listOfPolymers.get(i).toHELM2() + "}\""
            + listOfPolymers.get(i).getAnnotation() + "\"|");
      } else {
        notation.append(listOfPolymers.get(i).getPolymerID() + "{" + listOfPolymers.get(i).toHELM2() + "}" + "|");
      }
    }

    notation.setLength(notation.length() - 1);
    return notation.toString();
  }

  /**
   * method to generate a valid HELM2 string for the second section
   *
   * @return valid HELM2 String
   */
  public String connectionToHELM2() {
    if (listOfConnections.size() == 0) {
      return "";
    }
    StringBuilder notation = new StringBuilder();
    for (int i = 0; i < listOfConnections.size(); i++) {
      notation.append(listOfConnections.get(i).toHELM2() + "|");
    }

    notation.setLength(notation.length() - 1);
    return notation.toString();
  }

  /**
   * method to generate a valid HELM2 string for the third section
   *
   * @return valid HELM2 String
   */
  public String groupingToHELM2() {
    if (listOfGroupings.size() == 0) {
      return "";
    }
    StringBuilder notation = new StringBuilder();
    for (int i = 0; i < listOfGroupings.size(); i++) {
      notation.append(listOfGroupings.get(i).toHELM2() + "|");
    }

    notation.setLength(notation.length() - 1);
    return notation.toString();
  }

  /**
   * method to generate a valid HELM2 string for the fourth section
   *
   * @return valid HELM2 String
   */
  public String annotationToHELM2() {
    if (!(annotationSection.isEmpty())) {
      StringBuilder sb = new StringBuilder();
      for (int i = 0; i < annotationSection.size(); i++) {
        sb.append(annotationSection.get(i).toHELM2() + "|");
      }

      sb.setLength(sb.length() - 1);
      return sb.toString();
    }
    return "";
  }

  /**
   * method to get the ID's from all polymers and groups
   *
   * @return List of all ids from all polymers and groups
   */
  @JsonIgnore
  public List<String> getPolymerAndGroupingIDs() {
    List<String> listOfIDs = new ArrayList<String>();
    for (PolymerNotation polymer : listOfPolymers) {
      listOfIDs.add(polymer.getPolymerID().getId());
    }

    for (GroupingNotation grouping : listOfGroupings) {
      listOfIDs.add(grouping.getGroupID().getId());
    }
    return listOfIDs;
  }

  /**
   * method to get the ID's from all polymers
   *
   * @return list of all polymers ids
   */
  @JsonIgnore
  public List<String> getPolymerIDs() {
    List<String> listOfIDs = new ArrayList<String>();
    for (PolymerNotation polymer : listOfPolymers) {
      listOfIDs.add(polymer.getPolymerID().getId());
    }
    return listOfIDs;
  }

  /**
   * method to get the ID's from all polymers
   *
   * @return all ids from all polymers
   */
  @JsonIgnore
  public List<String> getGroupIDs() {
    List<String> listOfIDs = new ArrayList<String>();

    for (GroupingNotation grouping : listOfGroupings) {
      listOfIDs.add(grouping.getGroupID().getId());
    }
    return listOfIDs;
  }

  /**
   * method to get a specific polymer by its id
   *
   * @param id polymer id
   * @return polymer
   */
  @JsonIgnore
  public PolymerNotation getPolymerNotation(String id) {
    for (PolymerNotation polymer : listOfPolymers) {
      if (polymer.getPolymerID().getId().equals(id)) {
        return polymer;
      }
    }

    return null;
  }

}


/**
 * *****************************************************************************
 * Copyright C 2015, The Pistoia Alliance
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *****************************************************************************
 */
package org.helm.notation2.parser.notation.polymer;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.helm.notation2.parser.exceptionparser.HELM1ConverterException;
import org.helm.notation2.parser.exceptionparser.NotationException;
import org.helm.notation2.parser.notation.ValidationMethod;

import com.fasterxml.jackson.annotation.JsonIgnore;

/**
 * PolymerNotation class to represent a polymer with its content
 *
 * @author hecht
 */
public final class PolymerNotation {

  private PolymerEntity polymerID;

  private String annotation;

  @JsonIgnore
  private boolean annotationHere = false;

  private PolymerElements polymerElements = null;

  @JsonIgnore
  private Map<Integer, MonomerNotation> mapOfMonomers = new HashMap<Integer, MonomerNotation>();

  @JsonIgnore
  private Map<String, String> mapIntraConnection = new HashMap<String, String>();;

  public PolymerNotation() {

  }

  /**
   * Constructs with the given String
   *
   * @param str polymer ID
   * @throws NotationException if notation is not valid
   */
  public PolymerNotation(String str) throws NotationException {
    polymerID = (PolymerEntity) ValidationMethod.decideWhichEntity(str);
    setPolymerElements();
  }

  /**
   * Constructs with a given PolymerEnttiy, PolymerElements
   *
   * @param poly PolymerEntity
   * @param ele PolymerElements
   * @throws NotationException if notation is not valid
   */
  public PolymerNotation(PolymerEntity poly, PolymerElements ele) throws NotationException {
    this.polymerID = poly;
    this.polymerElements = ele;
  }

  /**
   * Constructs with a given PolymerEnttiy, PolymerElements and an annotation
   *
   * @param poly PolymerEntity
   * @param ele PolymerElements
   * @param anno new annotation
   */
  public PolymerNotation(PolymerEntity poly, PolymerElements ele, String anno) {
    this.polymerID = poly;
    this.polymerElements = ele;
    if (anno != null) {
      setAnnotation(anno);
    }
  }

  /**
   * method to generate the right PolymerElements, in the case of Chem and Blob
   * only one Monomer is allowed
   */
  private void setPolymerElements() {
    if (polymerID instanceof RNAEntity || polymerID instanceof PeptideEntity) {
      this.polymerElements = new PolymerListElements(polymerID);
    } else {
      this.polymerElements = new PolymerSingleElements(polymerID);
    }

  }

  /**
   * method to add/set the annotation
   *
   * @param str new annotation
   */
  private void setAnnotation(String str) {
    this.annotation = str;
    if (str != null) {
      this.annotationHere = true;
    }
  }

  /**
   * method to get the polymer entity
   *
   * @return polymer ID
   */
  public PolymerEntity getPolymerID() {
    return this.polymerID;
  }

  /**
   * method to get the PolymerElements
   *
   * @return PolymerElements
   */
  public PolymerElements getPolymerElements() {
    return this.polymerElements;
  }

  /**
   * method to get the annotation of the simple polymer
   *
   * @return annotation
   */
  public String getAnnotation() {
    return this.annotation;
  }

  /**
   * method to check if an annotation is there
   *
   * @return true if the annotation is there, false otherwise
   */
  public boolean isAnnotationHere() {
    return this.annotationHere;
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public String toString() {
    if (isAnnotationHere()) {
      return "PolymerID: " + polymerID + "\nElements: " + polymerElements.toString() + "Annotation: " + annotation;
    } else {
      return "PolymerID: " + polymerID + "\nElements: " + polymerElements.toString();
    }

  }

  /**
   * method to generate a valid HELM2 notation for this object
   *
   * @return valid HELM2 notation
   */
  public String toHELM2() {
    return this.polymerElements.toHELM2();
  }

  /**
   * method to generate a valid HELM notation for this object
   *
   * @return HELM notation in string format
   * @throws HELM1ConverterException if object can not downgraded to HELM1-Format
   */
  public String toHELM() throws HELM1ConverterException {
    if (polymerID instanceof BlobEntity) {
      throw new HELM1ConverterException("Can't be downgraded to HELM1-Format");
    }
    return this.polymerElements.toHELM();
  }

  @JsonIgnore
  public MonomerNotation getMonomerNotation(int count) {
    initializeMapOfMonomersAndMapOfIntraConnection();

    if (mapOfMonomers.containsKey(count)) {
      return mapOfMonomers.get(count);
    }
    return null;
  }

  public void initializeMapOfMonomersAndMapOfIntraConnection() {
    int multiply = 1;
    int value = 0;
    int lastValue = -1;
    for (MonomerNotation element : polymerElements.getListOfElements()) {
      try {
        // multiply = Integer.parseInt(element.getCount());
        multiply = 1;
        if (multiply < 1) {
          multiply = 1;
        }
      } catch (NumberFormatException ex) {
        multiply = 1;
      }

// if (element instanceof MonomerNotationList) {
// for (int z = 0; z < multiply; z++) {
// for (MonomerNotation monomerNotationUnit : ((MonomerNotationList)
// element).getListofMonomerUnits()) {
// value++;
// lastValue++;
// mapOfMonomers.put(value, monomerNotationUnit);
// if (lastValue != 0) {
// mapIntraConnection.put(lastValue + "$R2", "");
// mapIntraConnection.put(value + "$R1", "");
// }
// }
// }
// }
      if (element instanceof MonomerNotationUnitRNA) {
        for (int z = 0; z < multiply; z++) {
          lastValue = value;
          for (MonomerNotationUnit monomerNotationUnit : ((MonomerNotationUnitRNA) element).getContents()) {
            value++;
            mapOfMonomers.put(value, monomerNotationUnit);
          }

          /* Intra nucleotide Connections will be not scanned */
          if (value >= 4) {
            mapIntraConnection.put(lastValue + "$R2", "");
            int val = lastValue + 1;
            mapIntraConnection.put(val + "$R1", "");
          }
        }

      } else {
        for (int z = 0; z < multiply; z++) {
          value++;
          lastValue++;
          mapOfMonomers.put(value, element);
          if (lastValue != 0) {
            mapIntraConnection.put(lastValue + "$R2", "");
            mapIntraConnection.put(value + "$R1", "");
          }
        }

      }
    }
  }

  @JsonIgnore
  public Map<String, String> getMapIntraConnection() {
    return mapIntraConnection;
  }

  @JsonIgnore
  public List<MonomerNotation> getListMonomers() {
    List<MonomerNotation> listMonomerNotation = new ArrayList<MonomerNotation>();
    for (MonomerNotation monomerNotation : polymerElements.getListOfElements()) {
      if (monomerNotation instanceof MonomerNotationUnit) {
        listMonomerNotation.add(monomerNotation);
      } else {
        if (monomerNotation instanceof MonomerNotationGroup) {
          for (MonomerNotationGroupElement groupElement : ((MonomerNotationGroup) monomerNotation).getListOfElements()) {
            listMonomerNotation.add(groupElement.getMonomerNotation());
          }
        }
        if (monomerNotation instanceof MonomerNotationList) {
          listMonomerNotation.addAll(((MonomerNotationList) monomerNotation).getListofMonomerUnits());
        }
      }
    }
    return listMonomerNotation;
  }

}


/**
 * *****************************************************************************
 * Copyright C 2015, The Pistoia Alliance
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *****************************************************************************
 */
package org.helm.notation2.parser.simplepolymerssection;

import org.helm.notation2.parser.State;
import org.helm.notation2.parser.StateMachineParser;
import org.helm.notation2.parser.connectionsection.ConnectionsParser;
import org.helm.notation2.parser.exceptionparser.NotationException;
import org.helm.notation2.parser.exceptionparser.SimplePolymerSectionException;
import org.helm.notation2.parser.notation.polymer.PolymerNotation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * SimplePolymersParser class to parse the simple polymer id
 *
 * @author hecht
 */
public class SimplePolymersParser implements State {

  private String polymerId = "";

  private StateMachineParser _parser;

  private static final Logger LOG = LoggerFactory.getLogger(SimplePolymersParser.class);

  /**
   * Constructs with a state machine
   *
   * @param pParser StateMachineParser
   */
  public SimplePolymersParser(StateMachineParser pParser) {
    _parser = pParser;
  }

  /**
   * {@inheritDoc}
   *
   * @throws NotationException if notation is not valid
   * @throws SimplePolymerSectionException if simple polymer section is not valid
   */
  @Override
  public void doAction(char cha) throws SimplePolymerSectionException, NotationException {

    /* list of simple polymers is finished */
    if (cha == '$') {
      // id has to be empty
      if (polymerId == "") {
        if (!(_parser.isEmpty())) {
          LOG.info("Simple polymer section is finished:");
          LOG.info("Transition to connection section:");
          _parser.setState(new ConnectionsParser(_parser));
        } else {
          LOG.error("Simple polymer ID has to be defined:");
          throw new SimplePolymerSectionException("A simple polymer has to be defined");
        }
      } else {
        LOG.error("Incorrect input in the simple polymer section:");
        throw new SimplePolymerSectionException("Incorrect input in the simple polymer section:");
      }

    } /* simple polymer notation is starting */ else if (cha == '{') {
      if ((_parser.checkPolymerId(polymerId)) && polymerId != "") {
        LOG.info("Simple polymer ID is read:");
        _parser.notationContainer.addPolymer(new PolymerNotation(polymerId));
        _parser.addPolymer(polymerId);
        _parser.setState(new SimplePolymersNotationParser(_parser));
      } else {
        LOG.error("Polymer ID is not correct: " + polymerId);
        throw new SimplePolymerSectionException("Polymer ID is not correct: " + polymerId);
      }
    } /* add characters to polymer id */ else {
      polymerId += cha;
    }

  }

}


/**
 * *****************************************************************************
 * Copyright C 2015, The Pistoia Alliance
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *****************************************************************************
 */
package org.helm.notation2.parser.notation.grouping;

import java.text.DecimalFormat;

import org.helm.notation2.parser.exceptionparser.NotationException;

/**
 * GroupingAnd
 *
 * @author hecht
 */
public class GroupingMixture extends GroupingAmbiguity {

  private GroupingElement element;

  public GroupingMixture() {

  }

  /**
   * Constructs with the given String representing a list of grouping elements
   * Mixture with ratio or interval
   *
   * @param str whole group
   * @throws NotationException if notation is not valid
   */
  public GroupingMixture(String str) throws NotationException {
    /* Mixture elements are separated by + */
    String[] parts = str.split("\\+|\\(\\+|\\+\\)|\\(\\+\\)");
    for (int i = 0; i < parts.length; ++i) {
      /* Ratio can be defined -> default is 1 */
      String[] item = parts[i].split(":");
      double ratio = 1;
      double ratio2 = 1;
      boolean interval = false;
      boolean isDefault = true;
      if (item.length > 1) {
        /* an interval can be there or not */
        if (item[1].split("-").length > 1) {
          interval = true;
          ratio = Double.parseDouble(item[1].split("-")[0]);
          ratio2 = Double.parseDouble(item[1].split("-")[1]);
          isDefault = false;
        } else {
          /* unknown ratio */
          if (item[1].contains("?")) {
            ratio = -1;
          } else {
            ratio = Double.parseDouble(item[1]);
            isDefault = false;
          }
        }
      }

      if (!(interval)) {
        element = new GroupingElement(item[0], ratio, isDefault);
      } else {
        element = new GroupingElement(item[0], ratio, ratio2);
      }

      addElement(element);

    }

  }

  /**
   * {@inheritDoc}
   */
  @Override
  public String toHELM2() {
    DecimalFormat d = new DecimalFormat("#.##");
    StringBuilder notation = new StringBuilder();
    for (GroupingElement groupingElement : elements) {
      if (!(groupingElement.isDefaultValue())) {
        String value = d.format(groupingElement.getValue().get(0)).replace(',', '.');
        if (groupingElement.getValue().size() > 1) {
          value += "-" + d.format(groupingElement.getValue().get(1)).replace(',', '.');
        }
        notation.append(groupingElement.getID() + ":" + value + "+");
      } else {
        notation.append(groupingElement.getID() + "+");
      }

    }

    notation.setLength(notation.length() - 1);

    return notation.toString();
  }

}


/**
 * *****************************************************************************
 * Copyright C 2015, The Pistoia Alliance
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *****************************************************************************
 */
package org.helm.notation2.parser;

/**
 * ConverterHELM1ToHELM2
 *
 * @author hecht
 */
public class ConverterHELM1ToHELM2 {

  /**
   * Constructor to convert HELM1 into HELM2
   */
  public ConverterHELM1ToHELM2() {

  }

  /**
   * method to convert the given string into the HELM2 format
   *
   * @param str HELM1 Notation
   * @return HELM2 Notation
   */
  public String doConvert(String str) {

	//check for just missing V2.0

	  ParserHELM2 parser = new ParserHELM2();
	  try{
	  parser.parse(str + "V2.0");
	  return str + "V2.0";
	  }
	  catch(Exception e){

    /* Use String Builder */
    /* simple add character -> split works then */
    String helm1 = str + "f";

    StringBuilder helm2 = new StringBuilder();
    String[] sections = helm1.split("}\\$");

    /* Section 1 is accepted in full, no changes necessary, Section 1 has to be there */
    helm2.append(sections[0] + "}$");

    StringBuilder sb = new StringBuilder();
    for (int i = 1; i < sections.length; i++) {
      sb.append(sections[i] + "}$");
    }

    helm1 = "$" + sb.toString();
    sections = helm1.split("\\$");

     /*
     * Section 2 connection section; section 3 is added to the second section,
     * Section 2 is not necessary, is this section really there
     */
     if (sections.length >= 2) {
       if (!(sections[1].isEmpty())) {
        helm2.append(sections[1]);
       }
     }

     /* Add hydrogen bonds to the connection section */
     if (sections.length >= 3) {
       if (!(sections[2].isEmpty())) {

         if (!(sections[1].isEmpty())) {
          helm2.append("|" + sections[2]);
         } else {
          helm2.append(sections[2]);
         }
       }

       /*Group section*/
      helm2.append("$");

      helm2.append("$");

       /*Add annotation to the annotation section*/
       if (sections.length >= 4) {
         if (!(sections[3].isEmpty())) {
          helm2.append(sections[3]);
         }
       }

     }

    /* Add version number to indicate HELM2 notation */
    helm2.append("$V2.0");
    return helm2.toString();
	  }

  }
}


/**
 * *****************************************************************************
 * Copyright C 2015, The Pistoia Alliance
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *****************************************************************************
 */
package org.helm.notation2.parser.notation.polymer;

import org.helm.notation2.parser.exceptionparser.HELM1ConverterException;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonTypeInfo;

/**
 * MonomerNotation
 *
 *
 * @author shecht
 */
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "classType")
public abstract class MonomerNotation {
  protected String unit;

  protected String annotation;

  protected String count = String.valueOf(1);

  protected boolean isDefault = true;

  protected boolean isAnnotationHere = false;

  protected String type;

  public MonomerNotation() {

  }

  /**
   * Constructs with the given string
   *
   * @param str Monomer
   * @param type Type of polymer
   */
  public MonomerNotation(String str, String type) {
    this.unit = str;
    this.type = type;
    if (str.equals("?")) {
      setCount("0..n");
      isDefault = true;
    }
    if (str.equals("_")) {
      setCount("0");
      isDefault = true;
    }
    if (str.equals("*")) {
      setCount("0..n");
      isDefault = true;
    }

  }

  /**
   * method to get the ID of the Monomer
   *
   * @return ID
   */

  public String getUnit() {
    return unit;
  }

  /**
   * method to add annotation to this monomer
   *
   * @param str annotation
   */
  public void setAnnotation(String str) {
    if (str != null) {
      annotation = str;
      isAnnotationHere = true;
    } else {
      annotation = null;
      isAnnotationHere = false;
    }
  }

  /**
   * method to change the default count of one to the user-defined
   *
   * @param str user-defined count
   */
  public void setCount(String str) {
    isDefault = false;
    if (str.equals("1")) {
      isDefault = true;
    }

    count = str;
  }

  /**
   * method to get the count of the monomer
   *
   * @return count
   */
  public String getCount() {
    return count;
  }

  /**
   * method to get the annotation for this monomer
   *
   * @return annotation
   */
  public String getAnnotation() {
    return annotation;
  }

  /**
   * method to check if a annotation is there or not
   *
   * @return true, if the annotation is there, false otherwise
   */
  @JsonIgnore
  public boolean isAnnotationTrue() {
    return isAnnotationHere;
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public String toString() {
    if (isAnnotationTrue()) {
      return "Monomer unit: " + unit + "\nCount: " + count + "\nAnnotation: " + annotation;
    } else {
      return "Monomer unit: " + unit + "\nCount: " + count;
    }
  }

  /**
   * method to generate a valid HELM2
   *
   * @return valid HELM2
   */
  public abstract String toHELM2();

  /**
   * method to get the Type of Polymer
   *
   * @return type of polymer
   */
  public String getType() {
    return this.type;
  }

  /**
   * method to generate a valid HELM
   *
   * @return object in string format
   * @throws HELM1ConverterException if the object can not be downgraded to HELM1-Format
   */
  public abstract String toHELM() throws HELM1ConverterException;

}


/**
 * *****************************************************************************
 * Copyright C 2015, The Pistoia Alliance
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *****************************************************************************
 */
package org.helm.notation2.parser.notation;

import java.io.IOException;
import java.util.regex.Pattern;

import org.helm.notation2.parser.exceptionparser.NotationException;
import org.helm.notation2.parser.notation.polymer.BlobEntity;
import org.helm.notation2.parser.notation.polymer.ChemEntity;
import org.helm.notation2.parser.notation.polymer.GroupEntity;
import org.helm.notation2.parser.notation.polymer.HELMEntity;
import org.helm.notation2.parser.notation.polymer.MonomerNotation;
import org.helm.notation2.parser.notation.polymer.MonomerNotationGroupElement;
import org.helm.notation2.parser.notation.polymer.MonomerNotationGroupMixture;
import org.helm.notation2.parser.notation.polymer.MonomerNotationGroupOr;
import org.helm.notation2.parser.notation.polymer.MonomerNotationList;
import org.helm.notation2.parser.notation.polymer.MonomerNotationUnit;
import org.helm.notation2.parser.notation.polymer.MonomerNotationUnitRNA;
import org.helm.notation2.parser.notation.polymer.PeptideEntity;
import org.helm.notation2.parser.notation.polymer.RNAEntity;
import org.jdom2.JDOMException;

/**
 * Class containing validation methods
 *
 * @author hecht
 */
public final class ValidationMethod {

	/**
	 * Default constructor.
	 */
	private ValidationMethod() {

	}

	/**
	 * method to decide which of the MonomerNotation classes should be
	 * initialized
	 *
	 * @param str notation
	 * @param type polymer type
	 * @return MonomerNotation if monomer is not valid
	 * @throws NotationException if notation is not valid
	 */
	public static MonomerNotation decideWhichMonomerNotation(String str, String type)
			throws NotationException {
		MonomerNotation mon;
		/* group ? */
		if (str.startsWith("(") && str.endsWith(")")) {
			String str2 = str.substring(1, str.length() - 1);

			Pattern patternAND = Pattern.compile("\\+");
			Pattern patternOR = Pattern.compile(",");
			/* Mixture of elements */
			if (patternAND.matcher(str).find()) {
				mon = new MonomerNotationGroupMixture(str2, type);
			} /* or - groups */ else if (patternOR.matcher(str).find()) {
				mon = new MonomerNotationGroupOr(str2, type);
			} else {
				if (str.contains(".")) {
					mon = new MonomerNotationList(str2, type);
				} else {
					/* monomer unit is just in brackets */
					if (type == "RNA") {
						mon = new MonomerNotationUnitRNA(str2, type);
					} else {
						if (str2.length() > 1) {
							if (!(str2.startsWith("[") && str2.endsWith("]"))) {
								throw new NotationException("Monomers have to be in brackets: " + str);
							}
						}
						mon = new MonomerNotationUnit(str2, type);
					}
				}

			}
		} else {
			if (type == "RNA") {
				// if (str.startsWith("[") && str.endsWith("]")) {
				// mon = new MonomerNotationUnitRNA(str, type);
				// }
				mon = new MonomerNotationUnitRNA(str, type);
			} else if (type != "BLOB") {
				if (str.length() > 1) {
					if (!(str.startsWith("[") && str.endsWith("]"))) {
						throw new NotationException("Monomers have to be in brackets: " + str);
					}
				}
				mon = new MonomerNotationUnit(str, type);
			}
			else{
				mon = new MonomerNotationUnit(str, type);
			}

		}
		return mon;
	}

	/**
	 * method to decide which of the two Constructors of
	 * MonomerNotationGroupElement should be called
	 *
	 * @param str
	 *            Monomer
	 * @param type
	 *            polymer type of monomer
	 * @param one
	 *            count of Monomer
	 * @param two
	 *            count of Monomer
	 * @param interval
	 *            Has the monomer instead of one count an interval
	 * @param isDefault
	 *            Is the count of the monomer default = 1
	 * @return MonomerNotationGroupElement
	 * @throws NotationException if notation is not valid
	 */
	public static MonomerNotationGroupElement decideWhichMonomerNotationInGroup(String str, String type, double one,
			double two, boolean interval, boolean isDefault) throws NotationException{
		MonomerNotation element;

		element = decideWhichMonomerNotation(str, type);

		if (interval) {
			return new MonomerNotationGroupElement(element, one, two);
		} else {
			return new MonomerNotationGroupElement(element, one, isDefault);
		}
	}

	/**
	 * method to decide which of the Entities classes should be initialized
	 *
	 * @param str
	 *            polymer ID
	 * @return Entity
	 * @throws NotationException if the HELMEntity is not known, ID is not in the right format
	 */
	public static HELMEntity decideWhichEntity(String str) throws NotationException {

		HELMEntity item;

		if (str.toUpperCase().matches("PEPTIDE[1-9][0-9]*")) {
			item = new PeptideEntity(str.toUpperCase());
		} else if (str.toUpperCase().matches("RNA[1-9][0-9]*")) {
			item = new RNAEntity(str.toUpperCase());
		} else if (str.toUpperCase().matches("BLOB[1-9][0-9]*")) {
			item = new BlobEntity(str.toUpperCase());
		} else if (str.toUpperCase().matches("CHEM[1-9][0-9]*")) {
			item = new ChemEntity(str.toUpperCase());
		} else if (str.toUpperCase().matches("G[1-9][0-9]*")) {
			item = new GroupEntity(str.toUpperCase());
		} else {
			throw new NotationException("ID is wrong: " + str);
		}

		return item;

	}

}


/**
 * *****************************************************************************
 * Copyright C 2015, The Pistoia Alliance
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *****************************************************************************
 */
package org.helm.notation2.parser.connectionsection;

import java.io.IOException;

import org.helm.notation2.parser.InlineAnnotationsParser;
import org.helm.notation2.parser.State;
import org.helm.notation2.parser.StateMachineParser;
import org.helm.notation2.parser.exceptionparser.ConnectionSectionException;
import org.helm.notation2.parser.exceptionparser.NotationException;
import org.helm.notation2.parser.groupingsection.GroupingParser;
import org.helm.notation2.parser.notation.connection.ConnectionNotation;
import org.jdom2.JDOMException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * ConnectionsDetailsParser class to parse the details about the connection
 *
 * @author hecht
 */
public class ConnectionsDetailsParser implements State {
  private StateMachineParser _parser;

  private static final Logger LOG = LoggerFactory.getLogger(BetweenInlineConnectionParser.class);

  private String details = "";

  /**
   * Constructs with the state machine parser
   *
   * @param pParser current parser
   */
  public ConnectionsDetailsParser(StateMachineParser pParser) {
    _parser = pParser;
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public void doAction(char cha) throws ConnectionSectionException,
      NotationException{
    /* a new connection is starting */
    if (cha == '|') {
      if (_parser.checkDetailsConnections(details)) {
        LOG.info("A new connection is starting:");
        ConnectionNotation current =
            _parser.notationContainer.getCurrentConnection();
        _parser.notationContainer.changeConnectionNotation(new ConnectionNotation(
            current.getSourceId(),
            current.getTargetId(), details));

        _parser.setState(new ConnectionsParser(_parser));
      } else {
        LOG.error("Details about the connection are not corret: " + details);
        throw new ConnectionSectionException("Details about the connection are not correct: " + details);
      }

    } /* connection section is finished */ else if (cha == '$') {
      if (_parser.checkDetailsConnections(details)) {
        LOG.info("Connection section is finished:");
        ConnectionNotation current =
            _parser.notationContainer.getCurrentConnection();
        _parser.notationContainer.changeConnectionNotation(new ConnectionNotation(
            current.getSourceId(),
            current.getTargetId(), details));

        LOG.info("Transition to group section");
        _parser.setState(new GroupingParser(_parser));

      } else {
        throw new ConnectionSectionException("Details about the connection are not correct: " + details);
      }
    } /* start of an annotation */ else if (cha == '\"') {
      if (_parser.checkDetailsConnections(details)) {
        LOG.info("Add annotation to connection:");
        ConnectionNotation current =
            _parser.notationContainer.getCurrentConnection();
        _parser.notationContainer.changeConnectionNotation(new ConnectionNotation(
            current.getSourceId(),
            current.getTargetId(), details));

        _parser.setState(new InlineAnnotationsParser(_parser, 2));
      } else {
        LOG.error("Details about the connection are not corret: " + details);
        throw new ConnectionSectionException("Details about the connection are not correct: " + details);
      }

    } /* add characters to connection description */ else {
      details += cha;
    }
  }

}


/**
 * *****************************************************************************
 * Copyright C 2015, The Pistoia Alliance
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *****************************************************************************
 */
package org.helm.notation2.parser.groupingsection;

import org.helm.notation2.parser.State;
import org.helm.notation2.parser.StateMachineParser;
import org.helm.notation2.parser.annotationsection.AnnotationsParser;
import org.helm.notation2.parser.exceptionparser.GroupingSectionException;
import org.helm.notation2.parser.exceptionparser.NotationException;
import org.helm.notation2.parser.notation.grouping.GroupingNotation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * GroupingParser class to parse the group id
 *
 * @author hecht
 */
public class GroupingParser implements State {
  private StateMachineParser _parser;

  private String groupId = "";

  private static final Logger LOG = LoggerFactory.getLogger(GroupingParser.class);

  /**
   * Constructs with the state machine parser
   *
   * @param pParser current parser
   */
  public GroupingParser(StateMachineParser pParser) {
    _parser = pParser;
  }

  /**
   * {@inheritDoc}
   *
   * @throws NotationException if notation is not valid
   */
  @Override
  public void doAction(char cha) throws GroupingSectionException, NotationException {
    /*
     * group section is finished: section was empty: annotation section starts
     */
    if (cha == '$') {
      /* no details */
      if (groupId == "" && _parser.notationContainer.getListOfGroupings().size() == 0) {
        LOG.info("Group section is empty:");
        LOG.info("Transition to annotation section:");
        _parser.setState(new AnnotationsParser(_parser));
      } else {
        throw new GroupingSectionException("Missing details about the group: " + groupId);
      }

    } /* detailed information about the group is starting */ else if (cha == '(') {
      if (_parser.checkGroupId(groupId)) {
        LOG.info("Group ID is read:");
        _parser.notationContainer.addGrouping(new GroupingNotation(groupId));
        _parser.setState(new GroupingDetailedInformationParser(_parser));
      } else {
        LOG.error("Invalid group ID: " + groupId);
        throw new GroupingSectionException("Invalid group Id: " + groupId);
      }
    } /* add characters to the group id */ else {
      groupId += cha;
    }

  }
}


/**
 * *****************************************************************************
 * Copyright C 2015, The Pistoia Alliance
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *****************************************************************************
 */
package org.helm.notation2.parser.notation.polymer;

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

import com.fasterxml.jackson.annotation.JsonIgnore;

/**
 * MonomerNotationGroupElement
 *
 * @author hecht
 */
public class MonomerNotationGroupElement {
  private MonomerNotation monomer;

  private double numberOne;

  private double numberTwo;

  private boolean isInterval = false;

  private boolean isDefault = true;

  /**
   * Constructs with the MonomerNotation and the ratio
   *
   * @param not MonomerNotation
   * @param one value of the MonomerNotation
   * @param defaultValue if the value is a default value
   */
  public MonomerNotationGroupElement(MonomerNotation not, double one, boolean defaultValue) {
    this.monomer = not;
    this.numberOne = one;
    this.isDefault = defaultValue;

  }

  /**
   * Constructs with the MonomerNotation and a given interval according to two
   * numbers
   *
   * @param not MonomerNotation
   * @param one value of the MonomerNotation
   * @param two value of the MonomerNotation
   */
  public MonomerNotationGroupElement(MonomerNotation not, double one, double two) {
    this.monomer = not;
    this.numberOne = one;
    this.numberTwo = two;
    this.isInterval = true;
    this.isDefault = false;

  }

  /**
   * method the get the monomer
   *
   * @return MonomerNotation
   */
  public MonomerNotation getMonomerNotation() {
    return this.monomer;
  }

  public void setMonomerNotation(MonomerNotation mon) {
    this.monomer = mon;
  }

  /**
   * method to get the ratio or the interval of this group, in the case of an
   * interval it returns a list of two values
   *
   * @return List of the values
   */
  public List<Double> getValue() {
    if (this.isInterval) {
      return new ArrayList<Double>(Arrays.asList(numberOne, numberTwo));
    } else {
      return new ArrayList<Double>(Arrays.asList(numberOne));
    }

  }

  /**
   * method to check if the interval is there or not
   *
   * @return true if the interval is there, false otherwise
   */
  @JsonIgnore
  public boolean isInterval() {

    return isInterval;

  }

  /**
   * {@inheritDoc}
   */
  @Override
  public String toString() {
    if (isInterval) {
      return "ElementID: " + monomer.toString() + "\nIntervall: " + numberOne + "-" + numberTwo;
    }

    return "ElementID: " + monomer.toString() + "\nValue: " + numberOne;
  }

  /**
   * method to check if the value is a default one
   *
   * @return true if the value is default, false otherwise
   */
  @JsonIgnore
  public boolean isDefaultValue() {

    return isDefault;
  }

  /**
   * method to generate a valid HELM2 notation for this object
   *
   * @return valid HELM2 notation
   */
  public String toHELM2() {
    return monomer.getUnit();
  }

}


/**
 * *****************************************************************************
 * Copyright C 2015, The Pistoia Alliance
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *****************************************************************************
 */
package org.helm.notation2.parser;

import java.io.IOException;

import org.helm.notation2.parser.exceptionparser.ExceptionState;
import org.helm.notation2.parser.exceptionparser.FinalStateException;
import org.helm.notation2.parser.exceptionparser.NotValidHELM2Exception;
import org.helm.notation2.parser.notation.HELM2Notation;
import org.jdom2.JDOMException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * ParserHELM2 class to parse strings in the HELM2 format
 *
 * @author hecht
 */
public class ParserHELM2 {

  private StateMachineParser parser;

  private static final Logger LOG = LoggerFactory.getLogger(ParserHELM2.class);

  /**
   * method to parse the given HELM2 string in the case of an invalid HELM2 notation exception is thrown
   *
   * @param test HELM2 Notation
   * @throws ExceptionState if error occurs in state
   *
   */
  public void parse(String test) throws ExceptionState {

    parser = new StateMachineParser();
    test = test.trim();
    if (test.substring(test.length() - 4).matches("V2\\.0") || test.substring(test.length() - 4).matches("v2\\.0")) {

      for (int i = 0; i < test.length() - 4; i++) {
        parser.doAction(test.charAt(i));
      }

      if (!(parser.getState() instanceof FinalState)) {
        LOG.error("Invalid input: Final State was not reached:");
        throw new FinalStateException("Invalid input: Final State was not reached");
      }
    } else {
      LOG.error("Invalid input: HELM2 standard is missing:");
      throw new NotValidHELM2Exception("Invalid input: HELM2 standard is missing");
    }
  }

  /**
   * method to get from the read HELM2 notation the generated objects in the JSON-Output
   *
   * @return HELM2 in JSON-Output
   */
  public String getJSON() {
    return parser.toJSON();
  }

  /**
   * method to get from the read HELM2 notation a HELM2 notation
   *
   * @return HELM2Notation
   */
  public HELM2Notation getHELM2Notation() {
    return parser.notationContainer;
  }

}