package com.broadsoft.clients.cap;

import java.security.MessageDigest;
import java.io.UnsupportedEncodingException;

import java.util.Stack;
import java.text.SimpleDateFormat;
import java.util.Date;

public class TestClientUtil
{
  private static String charSet = System.getProperty ("file.encoding", "ISO-8859-1");

  private static MessageDigest sha;
  private static final int shaOutputLength = 40;  // 20 bytes * 2 chars/byte

  private static MessageDigest md5;
  private static final int md5OutputLength = 32;

  static
  {
    try
    {
      sha = MessageDigest.getInstance("SHA");
    }
    catch(Exception e)
    {
      System.err.println ("Failed to initialize SHA MessageDigest, Exception: " + e.getMessage());
    }

    try
    {
      md5 = MessageDigest.getInstance ("MD5");
    }
    catch (Exception e)
    {
      System.err.println ("Failed to initialize MD5 MessageDigest, Exception: " + e.getMessage());
    }
  }

  public static String shaMessageDigest (String plainText)
  {
    synchronized (sha)
    {
      // If message digest object wasn't initialized, then we're not
      // using this type of secure encoding.
      if (sha == null) return plainText;
      byte[] digestBytes;

      try
      {
        digestBytes = sha.digest (plainText.getBytes (charSet));
      }
      catch (UnsupportedEncodingException e)
      {
        System.err.println ("SHA Digest UnsupportedEncodingException: " + e.getMessage());
        return null;
      }

      char[] asciiDigestBytes = new char[shaOutputLength];
      for (int i = 0; i < (shaOutputLength / 2); i++)
      {
        int outputOffset = i * 2;
        byte thisByte = digestBytes[i];
        char upperNibble = toAsciiHexNibble( (thisByte & 0xF0) >> 4 );
        char lowerNibble = toAsciiHexNibble( thisByte & 0x0F );
        asciiDigestBytes[outputOffset] = upperNibble;
        asciiDigestBytes[outputOffset + 1] = lowerNibble;
      }
      String result = new String (asciiDigestBytes);

      sha.reset();
      return result;
    }
  }

  public static String md5MessageDigest (String plainText)
  {
    synchronized (md5)
    {
      // If message digest object wasn't initialized, then we're not
      // using this type of secure encoding.
      if (md5 == null) return plainText;

      // MessageDigest needs a byte[];
      byte[] plainBytes = null;

      try
      {
        plainBytes = plainText.getBytes (charSet);
      }
      catch (UnsupportedEncodingException e)
      {
        System.err.println ("MD5 Digest UnsupportedEncodingException: " + e.getMessage());
        return null;
      }

      // This should be 16 bytes.
      byte[] digestBytes = md5.digest (plainBytes);

      // We use the digest in ASCII Hex format (ASCII-encoded nibbles).  Convert.
      char[] asciiDigestBytes = new char[md5OutputLength];
      for (int i = 0; i < (md5OutputLength / 2); i++)
      {
        int outputOffset = i * 2;
        byte thisByte = digestBytes[i];
        char upperNibble = toAsciiHexNibble( (thisByte & 0xF0) >> 4 );
        char lowerNibble = toAsciiHexNibble( thisByte & 0x0F );
        asciiDigestBytes[outputOffset] = upperNibble;
        asciiDigestBytes[outputOffset + 1] = lowerNibble;
      }
      String result = new String(asciiDigestBytes);
      return result;
    }
  }

  private static char toAsciiHexNibble (int hexValue)
  {
    char returnValue = '!';   // default
    if( (hexValue >= 0) && (hexValue <= 9) )
    {
      returnValue = (char)((int)'0' + hexValue);
    }
    else if( (hexValue >= 0x000A) && (hexValue <= 0x000F) )
    {
      returnValue = (char)((int)'a' + (hexValue - 0x000A) );
    }
    return returnValue;
  }

    // Simple method to format the XML Output
  public static String formatOutput (String str)
  {
    Stack elemStack = new Stack();
    String retStr = new String();

    int fromIndx  = 0;
    int numTab = 0;

    while (fromIndx < str.length())
    {
      int startElemStartIndx = 0;
      int endElemStartIndx = 0;
      int endIndx = 0;

      if ((startElemStartIndx = str.indexOf("<", fromIndx)) >= 0)
      {
        startElemStartIndx++;

        if (str.charAt (startElemStartIndx) == '/')
        {
          int endElemEndIndx = str.indexOf (">", startElemStartIndx);
          String endElem = str.substring (startElemStartIndx + 1, endElemEndIndx);

          boolean forceTab = false;
          if (fromIndx < startElemStartIndx - 1)
          {
            // Field data
            retStr += str.substring (fromIndx, startElemStartIndx - 1);
          }
          else
          {
            // No field data, must have reached a terminating element
            retStr += newLine();
            forceTab = true;
          }

          if (elemStack.peek().equals (endElem))
          {
            elemStack.pop();
            numTab--;
            if (forceTab)
            {
              retStr += tab (numTab);
            }
            retStr += "</" + endElem + ">";
          }
          else
          {
            retStr += tab (--numTab);
            retStr += "</" + endElem + ">";
          }

          fromIndx = endElemEndIndx + 1;
        }
        else
        {
          // Start Element
          int startElemEndIndx = str.indexOf (">", startElemStartIndx);
          String startElem = str.substring (startElemStartIndx, startElemEndIndx);
          retStr += newLine() + tab (numTab) + "<" + startElem + ">";
          numTab++;
          fromIndx = startElemEndIndx + 1;
          elemStack.push (startElem);
        }
      }
    }

    retStr += newLine();

    return retStr;
  }

  private static String newLine()
  {
    return "\n";
  }

  private static String tab (int num)
  {
    String rv = "";
    while (num-- > 0)
    {
      rv += "  ";
    }
    return rv;
  }

  public static String getCurrentDataTime()
  {
    SimpleDateFormat formatter = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss:SSS zzz");
    Date currTime = new Date();
    String dateString = formatter.format (currTime);
    return dateString;
  }
}
