using System;
using System.Resources;
using System.Data.SqlClient;
using System.Configuration;
using Microsoft.ApplicationBlocks.Data;
using System.Data.SqlTypes;
using System.Data;

namespace Microsoft.RFIDLab.EPCISDemo.Common
{
	/// <summary>
	/// This class has methods for encoding and decoding Electronic Product Code
	/// (EPC) numbers 
	/// </summary>
	public class EPC
	{
		/// <summary>
		/// Encodes a barcode into its EPC equivalent
		/// </summary>
		/// <param name="barcodeNumber">Original barcode</param>
		/// <param name="sourceType">Original barcode type</param>
		/// <param name="targetType">EPC encoding required</param>
		/// <param name="serialNumber">Serial Number</param>
		/// <returns>Encoded EPC</returns>
		public static string Encode(string barcodeNumber, EPCEncoding targetType, int companyPrefixLength, int filterValue, int serialNumber, out string errorMessage)
		{
			string epc = "";
			int partitionValue;
			string companyPrefix;
			string itemReference;
			string binaryCompanyPrefix;
			string binaryItemReference;
			string binaryHeader;
			string binaryFilterValue;
			string binaryPartitionValue;
			string binarySerialNumber;
			int bitCompanyPrefixLength;
			string companyPrefixIndex;
			errorMessage = null;

			switch (targetType)
			{
					// Logic for encoding to SGTIN96 - Check EPC standards reference for 
					// more information
				case EPCEncoding.SGTIN96:
					partitionValue = GetPartition(companyPrefixLength);
					companyPrefix = barcodeNumber.Substring(1, companyPrefixLength);
					itemReference = barcodeNumber.Substring(0,1) + 
						barcodeNumber.Substring(companyPrefixLength + 1, 12 - companyPrefixLength);
					binaryCompanyPrefix = DecimalToBinary(Convert.ToInt64(companyPrefix)).PadLeft
						(GetCompanyPrefixLength(partitionValue, CompanyPrefixLengthMode.Bits), '0');
					binaryItemReference = DecimalToBinary(Convert.ToInt64(itemReference)).PadLeft
						(44 - GetCompanyPrefixLength(partitionValue, CompanyPrefixLengthMode.Bits), '0');
					// SGTIN header is decimal 48
					binaryHeader = "00110000";
					binaryFilterValue = DecimalToBinary(Convert.ToInt64(filterValue)).PadLeft(3, '0');
					binaryPartitionValue = DecimalToBinary(Convert.ToInt64(partitionValue)).PadLeft(3,'0');
					binarySerialNumber = DecimalToBinary(serialNumber).PadLeft(38, '0');

					epc = BinToHex(binaryHeader + binaryFilterValue + binaryPartitionValue +
						binaryCompanyPrefix + binaryItemReference + binarySerialNumber);
					break;
				case EPCEncoding.SGTIN64:
					partitionValue = GetPartition(companyPrefixLength);
					companyPrefix = barcodeNumber.Substring(1, companyPrefixLength);
					companyPrefixIndex = GetCompanyPrefixIndex(companyPrefix);
					itemReference = barcodeNumber.Substring(0,1) + 
						barcodeNumber.Substring(companyPrefixLength + 1, 12 - companyPrefixLength);
					string binaryCompanyPrefixIndex = DecimalToBinary(Convert.ToInt64(companyPrefixIndex)).PadLeft
						(14, '0');
					binaryItemReference = DecimalToBinary(Convert.ToInt64(itemReference)).PadLeft
						(20, '0');
					// SGTIN 64 header is decimal 2
					binaryHeader = "10";
					binaryFilterValue = DecimalToBinary(Convert.ToInt64(filterValue)).PadLeft(3, '0');
					binarySerialNumber = DecimalToBinary(serialNumber).PadLeft(25, '0');

					epc = BinToHex(binaryHeader + binaryFilterValue + binaryCompanyPrefixIndex +
						binaryItemReference + binarySerialNumber);
					break;
				case EPCEncoding.SSCC96:
					partitionValue = GetPartition(companyPrefixLength);
					companyPrefix = barcodeNumber.Substring(1, companyPrefixLength);

					bitCompanyPrefixLength = GetCompanyPrefixLength(partitionValue, CompanyPrefixLengthMode.Bits);
					binaryCompanyPrefix = DecimalToBinary(Convert.ToInt64(companyPrefix)).PadLeft
						(bitCompanyPrefixLength, '0');
					
					// SSCC header is decimal 49
					binaryHeader = "00110001";
					binaryFilterValue = DecimalToBinary(Convert.ToInt64(filterValue)).PadLeft(3, '0');
					binaryPartitionValue = DecimalToBinary(Convert.ToInt64(partitionValue)).PadLeft(3,'0');
					binarySerialNumber = DecimalToBinary(serialNumber).PadLeft(57 - bitCompanyPrefixLength, '0');

					// SSCC encoding ends in 25 binary zeros
					string binaryFiller = "0".PadLeft(25, '0');

					epc = BinToHex(binaryHeader + binaryFilterValue + binaryPartitionValue +
						binaryCompanyPrefix + binarySerialNumber + binaryFiller);
					break;
				case EPCEncoding.SSCC64:
					partitionValue = GetPartition(companyPrefixLength);
					companyPrefix = barcodeNumber.Substring(1, companyPrefixLength);
					companyPrefixIndex = GetCompanyPrefixIndex(companyPrefix);
					binaryHeader = "00001000";
					binaryFilterValue = DecimalToBinary(Convert.ToInt64(filterValue)).PadLeft(3, '0');
					binaryCompanyPrefixIndex = DecimalToBinary(Convert.ToInt64(companyPrefixIndex)).PadLeft
						(14, '0');
					binarySerialNumber = DecimalToBinary(serialNumber).PadLeft(39, '0');

					epc = BinToHex(binaryHeader + binaryFilterValue + binaryCompanyPrefixIndex +
						binarySerialNumber);
					break;
				default:
					errorMessage = "Invalid EPC Header. Currently supported header types are 64 and 96 bit SSCC and SGTIN";
					break;
			}
			return epc;
		}

		/// <summary>
		/// Decodes an EPC number to its UPC equivalent. Currently supports only GTIN
		/// </summary>
		/// <param name="hexEPC">Hexadecimal EPC encoded number</param>
		/// <param name="targetType">Required barcode type</param>
		/// <returns>Barcode</returns>
		public static string Decode(string hexEPC, BarcodeType targetType, out string errorMessage)
		{
			errorMessage = null;
			if (hexEPC.Length == 0)
			{
				throw new ApplicationException("EPC_INVALID_LENGTH");
			}
			string binaryEpc = HexToBin(hexEPC);
			string header;
			string itemIdentifier;

			
			
			// If EPC begins with "00", header field is 8 bits, else 2 bits
			// Ref: EPCTagDataSpecification11rev124 Page 16
			int headerLength;
			if (binaryEpc.Substring(0,2).Equals("00"))
			{
				headerLength = 8;
			}
			else
			{
				headerLength = 2;
			}
			
			header = binaryEpc.Substring(0, headerLength);
			switch (header)
			{
				case (Constants.SGTIN96Header):
				{
					// Retrieve the partition value from 11-13 bits of EPC and
					// get corresponding company prefix length
					Int64 partition = BinaryToDecimal(binaryEpc.Substring(11,3));
					int companyPrefixLengthBinary  = GetCompanyPrefixLength(Convert.ToInt32(partition), CompanyPrefixLengthMode.Bits);
					int companyPrefixLengthDecimal = GetCompanyPrefixLength(Convert.ToInt32(partition), CompanyPrefixLengthMode.Digits);
					
					// company prefix lengh + item reference length = 44 bits -
					// get length of item reference
					int itemReferenceLenghtBinary  = 44 - companyPrefixLengthBinary;
					int itemReferenceLenghtDecimal = 13 - companyPrefixLengthDecimal;
					string companyPrefix = BinaryToDecimal(binaryEpc.Substring(14, companyPrefixLengthBinary)).ToString().PadLeft(companyPrefixLengthDecimal, '0');
					string itemReference = BinaryToDecimal(binaryEpc.Substring(14 + companyPrefixLengthBinary, itemReferenceLenghtBinary)).ToString().PadLeft(itemReferenceLenghtDecimal, '0');

					// The first digit of item reference moves to the first position of EPC
					itemIdentifier = itemReference.Substring(0,1) + companyPrefix + itemReference.Substring(1, itemReference.Length - 1);
					string checkDigit = CalculateCheckDigit(itemIdentifier).ToString();;
					return itemIdentifier + checkDigit;
				}
				case (Constants.SGTIN64Header):
				{
					// Retrieve the company prefix index from bits 5-19
					string companyPrefixIndex = binaryEpc.Substring(5, 14);
					string decimalCompanyPrefixIndex = BinaryToDecimal(companyPrefixIndex).ToString();
					string companyPrefix = GetCompanyPrefix(decimalCompanyPrefixIndex);
					int itemReferenceLength = 13-companyPrefix.Length;
					string itemReference = binaryEpc.Substring(19, 20);
					string decimalItemReference = BinaryToDecimal(itemReference).ToString().PadLeft(itemReferenceLength, '0');;
					string checkDigitCalculator = decimalItemReference.Substring(0,1) + 
						companyPrefix + decimalItemReference.Substring(1, itemReferenceLength-1);

					string checkDigit = CalculateCheckDigit(checkDigitCalculator).ToString();;
					return checkDigitCalculator + checkDigit;
				}
				case (Constants.SSCC96Header):
				{
					string errorMessage1 = string.Format(ExceptionManager.GetErrorMessage("ERR_EPC_SSCCGTIN"), header);
					throw new ApplicationException(errorMessage1);
				}
				default:
				{
					errorMessage = string.Format(ExceptionManager.GetErrorMessage("INV_EPC_HEADER"), header);
					throw new ApplicationException(errorMessage);
				}
			}
		}

		/// <summary>
		/// Method to parse the EPC and generate URI notation
		/// </summary>
		/// <param name="hexEPC">Hexadecimal EPC encoded number</param>
		/// <returns>URI</returns>
		public static string GetURI(string hexEPC, out string errorMessage)
		{
			errorMessage = null;
			if (hexEPC.Length == 0)
			{
				throw new ApplicationException("EPC_INVALID_LENGTH");
			}
			string binaryEpc = HexToBin(hexEPC);
			string header;

			Int64 partition;
			int companyPrefixLengthBinary;
			int companyPrefixLengthDecimal;
			int itemReferenceLenghtBinary;
			int itemReferenceLenghtDecimal;
			string filterValue;
			string companyPrefix;
			string itemReference;
			string serialNumber;
			
			// If EPC begins with "00", header field is 8 bits, else 2 bits
			// Ref: EPCTagDataSpecification11rev124 Page 16
			int headerLength;
			if (binaryEpc.Substring(0,2).Equals("00"))
			{
				headerLength = 8;
			}
			else
			{
				headerLength = 2;
			}
			
			header = binaryEpc.Substring(0, headerLength);
			switch (header)
			{
				case (Constants.SGTIN96Header):
					// Retrieve the partition value from 11-13 bits of EPC and
					// get corresponding company prefix length
			
					partition = BinaryToDecimal(binaryEpc.Substring(11,3));
					companyPrefixLengthBinary  = GetCompanyPrefixLength(Convert.ToInt32(partition), CompanyPrefixLengthMode.Bits);
					companyPrefixLengthDecimal = GetCompanyPrefixLength(Convert.ToInt32(partition), CompanyPrefixLengthMode.Digits);
					
					// company prefix lengh + item reference length = 44 bits
					// get length of item reference
					itemReferenceLenghtBinary  = 44 - companyPrefixLengthBinary;
					itemReferenceLenghtDecimal = 13 - companyPrefixLengthDecimal;

					filterValue   = BinaryToDecimal(binaryEpc.Substring(8, 3)).ToString();
					companyPrefix = BinaryToDecimal(binaryEpc.Substring(14, companyPrefixLengthBinary)).ToString().PadLeft(companyPrefixLengthDecimal, '0');
					itemReference = BinaryToDecimal(binaryEpc.Substring(14 + companyPrefixLengthBinary, itemReferenceLenghtBinary)).ToString().PadLeft(itemReferenceLenghtDecimal, '0');
					serialNumber  = BinaryToDecimal(binaryEpc.Substring(58, binaryEpc.Length-58)).ToString();

					return string.Format("{0}{1}.{2}.{3}.{4}", Constants.SGTIN96Uri,
						filterValue, companyPrefix, itemReference, serialNumber);
				case (Constants.SSCC96Header):
					// Retrieve the partition value from 11-13 bits of EPC and
					// get corresponding company prefix length
			
					partition = BinaryToDecimal(binaryEpc.Substring(11,3));
					companyPrefixLengthBinary  = GetCompanyPrefixLength(Convert.ToInt32(partition), CompanyPrefixLengthMode.Bits);
					companyPrefixLengthDecimal = GetCompanyPrefixLength(Convert.ToInt32(partition), CompanyPrefixLengthMode.Digits);
					
					filterValue   = BinaryToDecimal(binaryEpc.Substring(8, 3)).ToString();
					companyPrefix = BinaryToDecimal(binaryEpc.Substring(14, companyPrefixLengthBinary)).ToString().PadLeft(companyPrefixLengthDecimal, '0');
					serialNumber  = BinaryToDecimal(binaryEpc.Substring(14 + companyPrefixLengthBinary, binaryEpc.Length - (14 + companyPrefixLengthBinary) - 25)).ToString();

					return string.Format("{0}{1}.{2}.{3}", Constants.SSCC96Uri,
						filterValue, companyPrefix, serialNumber);
				case (Constants.SSCC64Header):
				{
					filterValue   = BinaryToDecimal(binaryEpc.Substring(8, 3)).ToString();
					string companyPrefixIndex = BinaryToDecimal(binaryEpc.Substring(11, 14)).ToString();
					companyPrefix = GetCompanyPrefix(companyPrefixIndex);
					serialNumber  = BinaryToDecimal(binaryEpc.Substring(25, 39)).ToString();

					return string.Format("{0}{1}.{2}.{3}", Constants.SSCC64Uri,
						filterValue, companyPrefix, serialNumber);
				}
				case (Constants.SGTIN64Header):
				{
					filterValue   = BinaryToDecimal(binaryEpc.Substring(2, 3)).ToString();
					string companyPrefixIndex = BinaryToDecimal(binaryEpc.Substring(5, 14)).ToString();
					companyPrefix = GetCompanyPrefix(companyPrefixIndex);
					itemReference = BinaryToDecimal(binaryEpc.Substring(19, 20)).ToString();
					serialNumber  = BinaryToDecimal(binaryEpc.Substring(39, 25)).ToString();

					return string.Format("{0}{1}.{2}.{3}.{4}", Constants.SGTIN64Uri,
						filterValue, companyPrefix, itemReference, serialNumber);
				}
				default:
					errorMessage = string.Format(ExceptionManager.GetErrorMessage("INV_EPC_HEADER"), header);
					throw new ApplicationException(errorMessage);
			}		
		}

		/// <summary>
		/// Method to parse the EPC and generate URI notation for Verisign EPC IS
		/// Verisign EPC IS URI Notation does not require the filter value in the URI. 
		/// So the GetURI function has been modified here to remove the filter value from the notation.
		/// </summary>
		/// <param name="hexEPC">Hexadecimal EPC encoded number</param>
		/// <returns>URI</returns>
		public static string GetURIforEPCIS(string hexEPC, out string errorMessage)
		{
			errorMessage = null;
			if (hexEPC.Length == 0)
			{
				throw new ApplicationException("EPC_INVALID_LENGTH");
			}
			string binaryEpc = HexToBin(hexEPC);
			string header;

			Int64 partition;
			int companyPrefixLengthBinary;
			int companyPrefixLengthDecimal;
			int itemReferenceLenghtBinary;
			int itemReferenceLenghtDecimal;
			string filterValue;
			string companyPrefix;
			string itemReference;
			string serialNumber;
			
			// If EPC begins with "00", header field is 8 bits, else 2 bits
			// Ref: EPCTagDataSpecification11rev124 Page 16
			int headerLength;
			if (binaryEpc.Substring(0,2).Equals("00"))
			{
				headerLength = 8;
			}
			else
			{
				headerLength = 2;
			}
			
			header = binaryEpc.Substring(0, headerLength);
			switch (header)
			{
				case (Constants.SGTIN96Header):
					// Retrieve the partition value from 11-13 bits of EPC and
					// get corresponding company prefix length
			
					partition = BinaryToDecimal(binaryEpc.Substring(11,3));
					companyPrefixLengthBinary  = GetCompanyPrefixLength(Convert.ToInt32(partition), CompanyPrefixLengthMode.Bits);
					companyPrefixLengthDecimal = GetCompanyPrefixLength(Convert.ToInt32(partition), CompanyPrefixLengthMode.Digits);
					
					// company prefix lengh + item reference length = 44 bits
					// get length of item reference
					itemReferenceLenghtBinary  = 44 - companyPrefixLengthBinary;
					itemReferenceLenghtDecimal = 13 - companyPrefixLengthDecimal;

					filterValue   = BinaryToDecimal(binaryEpc.Substring(8, 3)).ToString();
					companyPrefix = BinaryToDecimal(binaryEpc.Substring(14, companyPrefixLengthBinary)).ToString().PadLeft(companyPrefixLengthDecimal, '0');
					itemReference = BinaryToDecimal(binaryEpc.Substring(14 + companyPrefixLengthBinary, itemReferenceLenghtBinary)).ToString().PadLeft(itemReferenceLenghtDecimal, '0');
					serialNumber  = BinaryToDecimal(binaryEpc.Substring(58, binaryEpc.Length-58)).ToString();

					return string.Format("{0}{1}.{2}.{3}", Constants.SGTIN96Uri,
						companyPrefix, itemReference, serialNumber);
				case (Constants.SSCC96Header):
					// Retrieve the partition value from 11-13 bits of EPC and
					// get corresponding company prefix length
			
					partition = BinaryToDecimal(binaryEpc.Substring(11,3));
					companyPrefixLengthBinary  = GetCompanyPrefixLength(Convert.ToInt32(partition), CompanyPrefixLengthMode.Bits);
					companyPrefixLengthDecimal = GetCompanyPrefixLength(Convert.ToInt32(partition), CompanyPrefixLengthMode.Digits);
					
					filterValue   = BinaryToDecimal(binaryEpc.Substring(8, 3)).ToString();
					companyPrefix = BinaryToDecimal(binaryEpc.Substring(14, companyPrefixLengthBinary)).ToString().PadLeft(companyPrefixLengthDecimal, '0');
					serialNumber  = BinaryToDecimal(binaryEpc.Substring(14 + companyPrefixLengthBinary, binaryEpc.Length - (14 + companyPrefixLengthBinary) - 25)).ToString();

					return string.Format("{0}{1}.{2}", Constants.SSCC96Uri,
						companyPrefix, serialNumber);
				case (Constants.SSCC64Header):
				{
					filterValue   = BinaryToDecimal(binaryEpc.Substring(8, 3)).ToString();
					string companyPrefixIndex = BinaryToDecimal(binaryEpc.Substring(11, 14)).ToString();
					companyPrefix = GetCompanyPrefix(companyPrefixIndex);
					serialNumber  = BinaryToDecimal(binaryEpc.Substring(25, 39)).ToString();

					return string.Format("{0}{1}.{2}", Constants.SSCC64Uri,
						companyPrefix, serialNumber);
				}
				case (Constants.SGTIN64Header):
				{
					filterValue   = BinaryToDecimal(binaryEpc.Substring(2, 3)).ToString();
					string companyPrefixIndex = BinaryToDecimal(binaryEpc.Substring(5, 14)).ToString();
					companyPrefix = GetCompanyPrefix(companyPrefixIndex);
					itemReference = BinaryToDecimal(binaryEpc.Substring(19, 20)).ToString();
					serialNumber  = BinaryToDecimal(binaryEpc.Substring(39, 25)).ToString();

					return string.Format("{0}{1}.{2}.{3}", Constants.SGTIN64Uri,
						companyPrefix, itemReference, serialNumber);
				}
				default:
					errorMessage = string.Format(ExceptionManager.GetErrorMessage("INV_EPC_HEADER"), header);
					throw new ApplicationException(errorMessage);
			}		
		}

		/// <summary>
		/// Identify merchandise type based on filter value field in EPC
		/// </summary>
		/// <param name="hexEPC">Hexadecimal EPC encoded number</param>
		/// <returns>Type of merchandise</returns>
		public static MerchandiseType IdentifyMerchandise(string hexEPC, out string errorMessage)
		{
			errorMessage = null;
			if (hexEPC.Length == 0)
			{
				throw new ApplicationException("EPC_INVALID_LENGTH");
			}
			string binaryEpc = HexToBin(hexEPC);
			Int64 filterValue;
			
			// If EPC begins with "00", header field is 8 bits, else 2 bits
			// Ref: EPCTagDataSpecification11rev124 Page 16
			int headerLength;
			if (binaryEpc.Substring(0,2).Equals("00"))
			{
				headerLength = 8;
			}
			else
			{
				headerLength = 2;
			}
			
			filterValue = BinaryToDecimal(binaryEpc.Substring(headerLength, 3));

			return (MerchandiseType)filterValue;
		}

		#region
		public static string GetEpcEncoding(string hexEPC, out string errorMessage)
		{
			errorMessage = null;
			if (hexEPC.Length == 0)
			{
				throw new ApplicationException("EPC_INVALID_LENGTH");
			}
			string binaryEpc = HexToBin(hexEPC);
			
			// If EPC begins with "00", header field is 8 bits, else 2 bits
			// Ref: EPCTagDataSpecification11rev124 Page 16
			int headerLength;
			if (binaryEpc.Substring(0,2).Equals("00"))
			{
				headerLength = 8;
			}
			else
			{
				headerLength = 2;
			}
			string header = binaryEpc.Substring(0, headerLength);
			switch (header)
			{
				case (Constants.SGTIN96Header):
					return (EPCEncoding.SGTIN96).ToString();
				case (Constants.SSCC96Header):
					return (EPCEncoding.SSCC96).ToString();
				case (Constants.SGTIN64Header):
					return (EPCEncoding.SGTIN64).ToString();
				case (Constants.SSCC64Header):
					return (EPCEncoding.SSCC64).ToString();
				default:
					errorMessage = string.Format(ExceptionManager.GetErrorMessage("INV_EPC_HEADER"), header);
					throw new ApplicationException(errorMessage);
			}
		}
		#endregion


		public static string GetEAN(string GTIN)
		{
			return GTIN.Substring(1, GTIN.Length - 1);
		}

		#region GetCompanyPrefixLength
		/// <summary>
		/// Returns the length of company prefix (binary) based on partition value
		/// </summary>
		/// <param name="partitionValue">Partition Value from EPC number</param>
		/// <param name="mode">Indicator for Binary or Decimal length</param>
		/// <returns></returns>
		private static int GetCompanyPrefixLength(int partitionValue, CompanyPrefixLengthMode mode)
		{
			switch (mode)
			{
				case CompanyPrefixLengthMode.Bits:
				switch (partitionValue)
				{
					case 0:
						return 40;
					case 1:
						return 37;
					case 2:
						return 34;
					case 3:
						return 30;
					case 4:
						return 27;
					case 5:
						return 24;
					case 6:
						return 20;
					default:
						string errorMessage = string.Format(ExceptionManager.GetErrorMessage("INV_EPC_PARTITION"), partitionValue);
						throw new ApplicationException(errorMessage);
				}
				case CompanyPrefixLengthMode.Digits:
				switch (partitionValue)
				{
					case 0:
						return 12;
					case 1:
						return 11;
					case 2:
						return 10;
					case 3:
						return 9;
					case 4:
						return 8;
					case 5:
						return 7;
					case 6:
						return 6;
					default:
						string errorMessage = string.Format(ExceptionManager.GetErrorMessage("INV_EPC_PARTITION"), partitionValue);
						throw new ApplicationException(errorMessage);
				}
				default:
					throw new ApplicationException(ExceptionManager.GetErrorMessage("INV_EPC_LENGTHMODE"));
			}
		}
		#endregion

		#region GetCompanyPrefixIndex
		public static string GetCompanyPrefixIndex(string companyPrefix)
		{
			SqlConnection connection = null;
			string errorMessage;
			string connectionString = ConfigurationSettings.AppSettings["ManufacturerString"];

			try
			{
				connection = new SqlConnection(connectionString);
				connection.Open();
			}
			catch
			{
				errorMessage = Constants.DB_NO_CONNECTION;
				throw new ApplicationException(errorMessage);
			}

			object result;
			try
			{
				result = SqlHelper.ExecuteScalar(connection, CommandType.StoredProcedure, "getCompanyPrefixIndex", new SqlParameter("@CompanyPrefix", companyPrefix));
			}
			catch (Exception exp)
			{
				throw exp;
			}
			finally
			{
				if(connection != null)
					connection.Dispose();
			}


			if (result == null)
			{
				errorMessage = string.Format(Constants.DB_PRODUCT_NOT_FOUND, "Company Prefix", companyPrefix);
				throw new ApplicationException(errorMessage);
			}

			return result.ToString();
		}
		#endregion

		#region GetCompanyPrefix
		public static string GetCompanyPrefix(string companyprefixIndex)
		{
			SqlConnection connection = null;
			string errorMessage;
			string connectionString = ConfigurationSettings.AppSettings["ManufacturerString"];

			try
			{
				connection = new SqlConnection(connectionString);
				connection.Open();
			}
			catch
			{
				errorMessage = Constants.DB_NO_CONNECTION;
				throw new ApplicationException(errorMessage);
			}

			object result;
			try
			{
				result = SqlHelper.ExecuteScalar(connection, CommandType.StoredProcedure, "getCompanyPrefix", new SqlParameter("@CompanyPrefixIndex", companyprefixIndex));
			}
			catch (Exception exp)
			{
				throw exp;
			}
			finally
			{
				if(connection != null)
					connection.Dispose();
			}


			if (result == null)
			{
				errorMessage = string.Format(Constants.DB_PRODUCT_NOT_FOUND, "Company Prefix Index", companyprefixIndex);
				throw new ApplicationException(errorMessage);
			}

			return result.ToString();
		}
		#endregion

		#region Private Methods
		#region HexToBin
		/// <summary>
		/// Convert a hexadecimal number to Binary
		/// </summary>
		/// <param name="hexNumber">Hexadecimal number</param>
		/// <returns>Binary representation as string</returns>
		private static string HexToBin(string hexNumber)
		{
			string inputNumber;
			string binaryNumber = "";

			//Pad input number with leading zeros to make number of digits as
			// multiple of 4
			if (hexNumber.Length%4!=0)
			{
				int paddedSize = Convert.ToInt32(hexNumber.Length/4)*4 + 4;
				inputNumber = hexNumber.PadLeft(paddedSize, '0');
			}
			else
			{
				inputNumber = hexNumber;
			}

			// Convert each digit of hexadecimal number to
			// equivalent binary
			foreach (char hexDigit in inputNumber)
			{
				string binaryBlock;
				switch (hexDigit)
				{
					case '0':
						binaryBlock = "0000";
						break;
					case '1':
						binaryBlock = "0001";
						break;
					case '2':
						binaryBlock = "0010";
						break;
					case '3':
						binaryBlock = "0011";
						break;
					case '4':
						binaryBlock = "0100";
						break;
					case '5':
						binaryBlock = "0101";
						break;
					case '6':
						binaryBlock = "0110";
						break;
					case '7':
						binaryBlock = "0111";
						break;
					case '8':
						binaryBlock = "1000";
						break;
					case '9':
						binaryBlock = "1001";
						break;
					case 'A':
						binaryBlock = "1010";
						break;
					case 'B':
						binaryBlock = "1011";
						break;
					case 'C':
						binaryBlock = "1100";
						break;
					case 'D':
						binaryBlock = "1101";
						break;
					case 'E':
						binaryBlock = "1110";
						break;
					case 'F':
						binaryBlock = "1111";
						break;
					default:
						string errorMessage = string.Format(ExceptionManager.GetErrorMessage("INV_HEX_DIGIT"), hexDigit);
						throw new ApplicationException(errorMessage);
				}
				binaryNumber += binaryBlock;
			}

			return binaryNumber;
		}
		#endregion

		#region BinToHex
		/// <summary>
		/// Convert a Binary number to hexadecimal
		/// </summary>
		/// <param name="binaryNumber">Binary number</param>
		/// <returns>Hexadecimal representation as string</returns>
		private static string BinToHex(string binaryNumber)
		{
			string inputNumber;
			string hexNumber = "";

			//Pad input number with leading zeros to make number of digits as
			// multiple of 4
			if (binaryNumber.Length%4!=0)
			{
				int paddedSize = Convert.ToInt32(binaryNumber.Length/4)*4 + 4;
				inputNumber = binaryNumber.PadRight(paddedSize, '0');
			}
			else
			{
				inputNumber = binaryNumber;
			}

			// Convert each digit of hexadecimal number to
			// equivalent binary
			for (int i = 0; i < inputNumber.Length; i = i + 4)
			{
				string binaryBlock = inputNumber.Substring(i, 4);
				string hexDigit;
				switch (binaryBlock)
				{
					case "0000":
						hexDigit = "0";
						break;
					case "0001":
						hexDigit = "1";
						break;
					case "0010":
						hexDigit = "2";
						break;
					case "0011":
						hexDigit = "3";
						break;
					case "0100":
						hexDigit = "4";
						break;
					case "0101":
						hexDigit = "5";
						break;
					case "0110":
						hexDigit = "6";
						break;
					case "0111":
						hexDigit = "7";
						break;
					case "1000":
						hexDigit = "8";
						break;
					case "1001":
						hexDigit = "9";
						break;
					case "1010":
						hexDigit = "A";
						break;
					case "1011":
						hexDigit = "B";
						break;
					case "1100":
						hexDigit = "C";
						break;
					case "1101":
						hexDigit = "D";
						break;
					case "1110":
						hexDigit = "E";
						break;
					case "1111":
						hexDigit = "F";
						break;
					default:
						string errorMessage = string.Format(ExceptionManager.GetErrorMessage("INV_HEX_DIGIT"), binaryBlock);
						throw new ApplicationException(errorMessage);
				}
				hexNumber += hexDigit;
			}

			return hexNumber;
		}
		#endregion

		#region BinaryToDecimal
		/// <summary>
		/// Converts binary number to decimal
		/// </summary>
		/// <param name="binaryNumber">Number in binary format</param>
		/// <returns>Decimal number</returns>
		private static Int64 BinaryToDecimal(string binaryNumber)
		{
			Int64 decimalNumber = 0;
			int lastIndex = binaryNumber.Length - 1;
			// Starting from the last digit, convert each character into
			// 1 or 0 and use following logic -
			// For a number N5 N4 N3 N2 N1 N0 (eg. 10110)
			// 2^5*N5 + 2^4*N4 + 2^3*N3 + 2^2N2 + 2^1*N1 + 2^0*N0
			for (int index = lastIndex; index >= 0; index--)
			{
				int binaryDigit = Convert.ToInt16(binaryNumber.Substring(index, 1));
				decimalNumber += Convert.ToInt64(Math.Pow(2,Convert.ToDouble(lastIndex - index)) * binaryDigit);
			}

			return decimalNumber;
		}
		#endregion

		#region DecimalToBinary
		/// <summary>
		/// Converts decimal number to binary
		/// </summary>
		/// <param name="decimalNumber">Number in decimal format</param>
		/// <returns>Decimal number</returns>
		private static string DecimalToBinary(Int64 decimalNumber)
		{
			string convertedNumber    = "";
			Int64 inputNumber = decimalNumber;
			int digit;
			// Convert the decimal to binary using standard coversion routine
			while (inputNumber > 0)
			{
				digit = Convert.ToInt32(inputNumber%2);
				inputNumber = inputNumber/2;
				convertedNumber += digit.ToString();
			}
			// Reverse the number so formed
			string outputBinaryNumber = "";
			for (int i = convertedNumber.Length - 1; i >= 0; i --)
			{
				outputBinaryNumber += convertedNumber[i];
			}
			return outputBinaryNumber;
		}
		#endregion

		

		#region GetPartition
		/// <summary>
		/// Returns the partition value based on length of company prefix
		/// </summary>
		/// <param name="companyPrefixLength">Length of company prefix</param>
		/// <returns>Partition Value</returns>
		private static int GetPartition(int companyPrefixLength)
		{
			switch (companyPrefixLength)
			{
				case 12:
					return 0;
				case 11:
					return 1;
				case 10:
					return 2;
				case 9:
					return 3;
				case 8:
					return 4;
				case 7:
					return 5;
				case 6:
					return 6;
				default:
					string errorMessage = string.Format(Constants.INV_EPC_PARTITION);
					throw new ApplicationException(errorMessage);
			}
		}
		#endregion

		#region CalculateCheckDigit		
		/// <summary>
		/// Calculate check digit for UPC
		/// </summary>
		/// <param name="UPC"></param>
		/// <returns></returns>
		private static int CalculateCheckDigit(string UPC)
		{
			int lastIndex = UPC.Length - 1;

			int oddDigitSum  = 0;
			int evenDigitSum = 0;
			
			// Sum even digits
			for (int index = lastIndex; index >= 0; index=index-2)
			{
				evenDigitSum += Convert.ToInt32(UPC.Substring(index, 1));
			}
			// Sum odd digits
			for (int index = lastIndex - 1; index >= 0; index=index-2)
			{
				oddDigitSum += Convert.ToInt32(UPC.Substring(index, 1));
			}

			// Calculate chech digit as (3*oddDigitSum + evenDigitSum) MOD 10
			int modulo = ((3*oddDigitSum) + (evenDigitSum))%10;
			if (modulo == 0)
				return 0;
			else
				return (10 - modulo);
		}
		#endregion
		#endregion
	}

	#region Enumerators
	/// <summary>
	/// Barcode types
	/// </summary>
	public enum BarcodeType
	{
		UCC12 = 1,
		EAN13 = 2,
		GTIN  = 3
	}

	/// <summary>
	/// EPC encoding types
	/// </summary>
	public enum EPCEncoding
	{
		SGTIN96 = 48,
		SSCC96  = 49,
		SGTIN64 = 2,
		SSCC64  = 8
	}

	/// <summary>
	/// Type of merchandise - This is the filter value field in EPC
	/// and is used to identify the type of merchandise
	/// </summary>
	public enum MerchandiseType
	{
		Product = 1,
		Item    = 2,
		Case    = 3,
		Pallet  = 4
	}

	/// <summary>
	/// Has two values - Bits and Digits denoting length of company prefix in binary
	/// or decimal mode
	/// </summary>
	public enum CompanyPrefixLengthMode
	{
		Bits = 1,
		Digits = 2
	}
	#endregion
}
