/**
  * Receives a message from a COM port, processes it and outputs the formatted result to the given
  * COM Port Client window.
  *
  * @param aMessage The received message from the COM port
  * @param cpcParent The parent window to which the formatted output will be sent
  */
 public MsgFormatter(String aMessage, COMPortClient cpcParent) {
   log = LoggerFactory.getLogger(className);
   parent = cpcParent;
   originatingPort = parent.getPortName();
   incomingMessage = aMessage;
   formattedMessage = new Object[6];
   formatMessage();
 }
  /**
   * Takes the provided array of objects and stores the contents in the back-end database. The array
   * is expected to contain the following objects:
   *
   * <ul>
   *   <li>0 - Severity (String)
   *   <li>1 - PSE node name (String)
   *   <li>2 - Link ID (String)
   *   <li>3 - Received Error Message (String)
   *   <li>4 - Date received from the PSE (String)
   *   <li>5 - The universally unique identifier of the message (String)
   * </ul>
   *
   * @param dataToStore An object array in the format mentioned above.
   */
  public void storeDataInDb(Object[] dataToStore) {
    final int WORKED_OK = 1;
    final int DISCOVERED_NEW_LINK = 2;
    final int DISCOVERED_DUPLICATES = 3;
    final int ERROR_ENCOUNTERED = 4;
    final int NO_ENTRIES_FOUND = 5;
    final int DISCOVERED_LINK_MESSAGE = 6;

    DbInterface dbI = new DbInterface(originatingPort);
    int x = dbI.storeMessage(formattedMessage);
    switch (x) {
      case WORKED_OK:
        {
          // storeMessage worked without any problems.
          log.finest("Message saved in the database with a UUID of: " + formattedMessage[5]);
          String msg = (String) formattedMessage[3];
          Object[] linkState = new Object[3];
          linkState[0] = formattedMessage[1];
          linkState[1] = formattedMessage[2];
          linkState[2] = new Integer(LINK_STATE_UNKNOWN);
          if (msg.equals("LINK DOWN")) {
            linkState[2] = new Integer(LINK_STATE_DOWN);
            parent.setLinkData(linkState);
          }
          if (msg.equals("LINK UP")) {
            linkState[2] = new Integer(LINK_STATE_UP);
            parent.setLinkData(linkState);
          }
          break;
        }
      case DISCOVERED_NEW_LINK:
        {
          // storeMessage detected that this link was from a new link not in the database.
          String msg = (String) formattedMessage[3];
          if (msg.equals("LINK DOWN")) {
            parent.addNewLink(
                (String) formattedMessage[1], (String) formattedMessage[2], LINK_STATE_DOWN);
          } else if (msg.equals("LINK UP")) {
            parent.addNewLink(
                (String) formattedMessage[1], (String) formattedMessage[2], LINK_STATE_UP);
          } else {
            parent.addNewLink(
                (String) formattedMessage[1], (String) formattedMessage[2], LINK_STATE_UNKNOWN);
          }
          break;
        }
      case DISCOVERED_DUPLICATES:
        {
          // storeMessage detected duplicates in the database. Generate a warning to the user.
          log.severe(
              "Duplicates in the index of tblCodexLinks were detected while trying to save the received message.");
          System.err.println(
              "Duplicates were detected in the index of tblCodexLinks. Your database may be corrupt.");
          break;
        }
      case ERROR_ENCOUNTERED:
        {
          // storeMessage encountered an exception
          log.warning(
              "storeMessage() encountered an exception. The message it was trying to save may not have been entered into the database.");
          System.err.println(
              "An exception was detected while trying to save the message in the database. The data may not have been saved, please check the logs for more information.");
          break;
        }
      case DISCOVERED_LINK_MESSAGE:
        {
          String msg = (String) formattedMessage[3];
          if (msg.equals("LINK DOWN")) {
            parent.addNewLink(
                (String) formattedMessage[1], (String) formattedMessage[2], LINK_STATE_DOWN);
          } else if (msg.equals("LINK UP")) {
            parent.addNewLink(
                (String) formattedMessage[1], (String) formattedMessage[2], LINK_STATE_UP);
          } else {
            parent.addNewLink(
                (String) formattedMessage[1], (String) formattedMessage[2], LINK_STATE_UNKNOWN);
          }
          break;
        }
      default:
        {
          // storeMessage returned a value that wasn't recognised
          log.warning("storeMessage returned an unexpected value: " + x);
          break;
        }
    }
  }
  /**
   * Examines the contents of the string passed as a received message and checks it for problems. If
   * there is any reasons why the string may be considered erroneous then it is thrown out. Accepted
   * strings are broken into their constituent parts and stored in the back-end database and
   * outputted to the screen.
   *
   * <p>Checks against the contents of the received message are performed in the following order:
   *
   * <ul>
   *   <li>Is the string greater than 33 characters?
   *   <li>Does the string have '(', ')' or ' '?
   *   <li>Is the first token (from the start of the string to the first space) in the format (n)?
   *   <li>Is the token for the PSE name less than or equal to 8 characters?
   * </ul>
   *
   * If any of these checks fail then the string being processed is rejected and considered to be a
   * transmission error, error in configuration or link error.
   */
  public void formatMessage() {
    log.finer("Starting processing of message: " + incomingMessage);
    // Trim any whitespace from the string
    incomingMessage = incomingMessage.trim();
    if (incomingMessage.length() < 33) {
      // If the string is too short then throw it out
      return;
    }
    if (!incomingMessage.contains("(")
        && !incomingMessage.contains(")")
        && !incomingMessage.contains(" ")) {
      // If the string doesn't contain any brackets (parentheses) or spaces then throw it out
      return;
    }
    StringTokenizer stMsg = new StringTokenizer(incomingMessage);
    String token = "";
    String nextToken = "";
    String sSev = "5"; // Messages received should vary from 1-4. This is to spot problems
    token = stMsg.nextToken();
    if (token.length() != 3 && !token.startsWith("(") && !token.endsWith(")")) {
      // The first token should be the severity level of the message and be in the format (n).
      // If it's too long or not in the right format then throw the message out.
      return;
    } else {
      sSev = token.substring(1, 2);
    }
    // Second token should be the PSE name
    token = stMsg.nextToken();
    nextToken = stMsg.nextToken();
    String sPSENode = "";
    if (token.length() < 8) {
      // See if the next token is part of the PSE name.
      // If the total length of the two strings is 8 or less then they're part of the PSE name
      if ((token.length() + nextToken.length()) <= 8) {
        sPSENode = token + nextToken;
        nextToken = "";
      } else {
        sPSENode = token;
      }

    } else if (token.length() == 8) {
      sPSENode = token;
    } else {
      // The value for the token is too long to be a valid PSE name so throw it out.
      return;
    }
    // Try and get the date. If the nextToken is blank then we need to get the
    // date. If not then it holds the date
    if (nextToken.equals("")) {
      token = stMsg.nextToken(); // This will put the date into the token string
      nextToken = stMsg.nextToken(); // This will put the time into the next string
    } else {
      token = nextToken.toString(); // Move the date into the first string
      nextToken = stMsg.nextToken(); // Get the time and place into the second string
    }
    String sDate = "";
    String sDay = token.substring(0, 2);
    String sMonth = token.substring(3, 6);
    String sYear = token.substring(7, 11);
    String sHour = nextToken.substring(0, 2);
    String sMin = nextToken.substring(3, 5);
    if (sMonth.equals("JAN")) {
      sMonth = "01";
    }
    if (sMonth.equals("FEB")) {
      sMonth = "02";
    }
    if (sMonth.equals("MAR")) {
      sMonth = "03";
    }
    if (sMonth.equals("APR")) {
      sMonth = "04";
    }
    if (sMonth.equals("MAY")) {
      sMonth = "05";
    }
    if (sMonth.equals("JUN")) {
      sMonth = "06";
    }
    if (sMonth.equals("JUL")) {
      sMonth = "07";
    }
    if (sMonth.equals("AUG")) {
      sMonth = "08";
    }
    if (sMonth.equals("SEP")) {
      sMonth = "09";
    }
    if (sMonth.equals("OCT")) {
      sMonth = "10";
    }
    if (sMonth.equals("NOV")) {
      sMonth = "11";
    }
    if (sMonth.equals("DEC")) {
      sMonth = "12";
    }
    sDate = new String(sDay + "/" + sMonth + "/" + sYear + " " + sHour + ":" + sMin);
    sDay = null;
    sMonth = null;
    sYear = null;
    sHour = null;
    sMin = null;

    String sLinkID = "?";
    String sError = "";
    token = stMsg.nextToken();
    boolean hasChannel = false;
    String sChannel = "";
    if ((token.length() < 7) && token.contains("-")) {
      // We've got to pick out the link id on the PSE
      sLinkID = token.toString();
      // Skip the next token as it's only a hyphen
      token = stMsg.nextToken();
    }
    if (token.length() < 11 && token.contains("(") && token.contains(")")) {
      // If the code enters here then the token includes the channel number X25-nn(xx)
      sLinkID = token.substring(0, token.indexOf("("));
      sChannel = "on channel " + token.substring(token.indexOf("(") + 1, token.indexOf(")"));
      hasChannel = true;
      // Skip the next token as it's only a hyphen
      token = stMsg.nextToken();
    }
    if (token.equals("-")) {
      token = stMsg.nextToken();
      sError = sError + token + " ";
    } else {
      sError = sError + token + " ";
    }
    while (stMsg.hasMoreTokens()) {
      token = stMsg.nextToken();
      sError = sError + token + " ";
    }
    if (hasChannel) {
      sError = sError + sChannel;
    }
    sError = sError.trim();
    log.finer(sSev + ", " + sPSENode + ", " + sDate + ", " + sLinkID + ", " + sError);

    // Severity, PSE, Link, Message, Received, Unique ID
    formattedMessage[0] = sSev;
    formattedMessage[1] = sPSENode;
    formattedMessage[2] = sLinkID;
    formattedMessage[3] = sError;
    formattedMessage[4] = sDate;
    formattedMessage[5] = UUID.randomUUID().toString();

    log.entering("formatMessage", "UnformattedMessage.storeDataInDb(String)", formattedMessage);
    storeDataInDb(formattedMessage);
    log.entering(
        "formatMessage",
        "JNGui.Client.addAlarmData(String, String)",
        new Object[] {formattedMessage, originatingPort});
    parent.addAlarmData(formattedMessage);
  }