context: /*
   * Copyright 2006-2007 Jeremias Maerki.
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  using System;
  using System.Text;
  
  namespace ZXing.Datamatrix.Encoder
  {
     /// <summary>
     /// DataMatrix ECC 200 data encoder following the algorithm described in ISO/IEC 16022:200(E) in
     /// annex S.
     /// </summary>
     internal static class HighLevelEncoder
     {
        /// <summary>
        /// Padding character
        /// </summary>
        public const char PAD = (char)129;
        /// <summary>
        /// mode latch to C40 encodation mode
        /// </summary>
        public const char LATCH_TO_C40 = (char)230;
        /// <summary>
        /// mode latch to Base 256 encodation mode
        /// </summary>
        public const char LATCH_TO_BASE256 = (char)231;
        /// <summary>
        /// FNC1 Codeword
        /// </summary>
        public const char FNC1 = (char)232;
        /// <summary>
        /// Structured Append Codeword
        /// </summary>
        public const char STRUCTURED_APPEND = (char)233;
        /// <summary>
        /// Reader Programming
        /// </summary>
        public const char READER_PROGRAMMING = (char)234;
        /// <summary>
        /// Upper Shift
        /// </summary>
        public const char UPPER_SHIFT = (char)235;
        /// <summary>
        /// 05 Macro
        /// </summary>
        public const char MACRO_05 = (char)236;
        /// <summary>
        /// 06 Macro
        /// </summary>
        public const char MACRO_06 = (char)237;
        /// <summary>
        /// mode latch to ANSI X.12 encodation mode
        /// </summary>
        public const char LATCH_TO_ANSIX12 = (char)238;
        /// <summary>
        /// mode latch to Text encodation mode
        /// </summary>
        public const char LATCH_TO_TEXT = (char)239;
        /// <summary>
        /// mode latch to EDIFACT encodation mode
        /// </summary>
        public const char LATCH_TO_EDIFACT = (char)240;
        /// <summary>
        /// ECI character (Extended Channel Interpretation)
        /// </summary>
        public const char ECI = (char)241;
  
        /// <summary>
        /// Unlatch from C40 encodation
        /// </summary>
        public const char C40_UNLATCH = (char)254;
        /// <summary>
        /// Unlatch from X12 encodation
        /// </summary>
        public const char X12_UNLATCH = (char)254;
  
        /// <summary>
        /// 05 Macro header
        /// </summary>
        public const String MACRO_05_HEADER = "[)>\u001E05\u001D";
        /// <summary>
        /// 06 Macro header
        /// </summary>
        public const String MACRO_06_HEADER = "[)>\u001E06\u001D";
        /// <summary>
        /// Macro trailer
        /// </summary>
        public const String MACRO_TRAILER = "\u001E\u0004";
  
        /// <summary>
        /// Converts the message to a byte array using the default encoding (cp437) as defined by the
        /// specification
        /// </summary>
        /// <param name="msg">the message</param>
        /// <returns>the byte array of the message</returns>
        public static byte[] getBytesForMessage(String msg)
        {
           return Encoding.GetEncoding("CP437").GetBytes(msg); //See 4.4.3 and annex B of ISO/IEC 15438:2001(E)
        }
  
        private static char randomize253State(char ch, int codewordPosition)
        {
           int pseudoRandom = ((149 * codewordPosition) % 253) + 1;
           int tempVariable = ch + pseudoRandom;
           return tempVariable <= 254 ? (char)tempVariable : (char)(tempVariable - 254);
        }
  
        /// <summary>
        /// Performs message encoding of a DataMatrix message using the algorithm described in annex P
        /// of ISO/IEC 16022:2000(E).
        /// </summary>
        /// <param name="msg">the message</param>
        /// <returns>the encoded message (the char values range from 0 to 255)</returns>
        public static String encodeHighLevel(String msg)
        {
           return encodeHighLevel(msg, SymbolShapeHint.FORCE_NONE, null, null, Encodation.ASCII);
        }
  
        /// <summary>
        /// Performs message encoding of a DataMatrix message using the algorithm described in annex P
        /// of ISO/IEC 16022:2000(E).
        /// </summary>
        /// <param name="msg">the message</param>
        /// <param name="shape">requested shape. May be {@code SymbolShapeHint.FORCE_NONE},{@code SymbolShapeHint.FORCE_SQUARE} or {@code SymbolShapeHint.FORCE_RECTANGLE}.</param>
        /// <param name="minSize">the minimum symbol size constraint or null for no constraint</param>
        /// <param name="maxSize">the maximum symbol size constraint or null for no constraint</param>
        /// <returns>the encoded message (the char values range from 0 to 255)</returns>
        public static String encodeHighLevel(String msg,
                                             SymbolShapeHint shape,
                                             Dimension minSize,
                                             Dimension maxSize,
                                             int defaultEncodation)
        {
           //the codewords 0..255 are encoded as Unicode characters
           Encoder[] encoders =
              {
                 new ASCIIEncoder(), new C40Encoder(), new TextEncoder(),
                 new X12Encoder(), new EdifactEncoder(), new Base256Encoder()
              };
  
           var context = new EncoderContext(msg);
           context.setSymbolShape(shape);
           context.setSizeConstraints(minSize, maxSize);
  
           if (msg.StartsWith(MACRO_05_HEADER) && msg.EndsWith(MACRO_TRAILER))
           {
              context.writeCodeword(MACRO_05);
              context.setSkipAtEnd(2);
              context.Pos += MACRO_05_HEADER.Length;
           }
           else if (msg.StartsWith(MACRO_06_HEADER) && msg.EndsWith(MACRO_TRAILER))
           {
              context.writeCodeword(MACRO_06);
              context.setSkipAtEnd(2);
              context.Pos += MACRO_06_HEADER.Length;
           }
  
           int encodingMode = defaultEncodation; //Default mode
           switch (encodingMode)
           {
              case Encodation.BASE256:
                 context.writeCodeword(HighLevelEncoder.LATCH_TO_BASE256);
                 break;
              case Encodation.C40:
                 context.writeCodeword(HighLevelEncoder.LATCH_TO_C40);
                 break;
              case Encodation.X12:
                 context.writeCodeword(HighLevelEncoder.LATCH_TO_ANSIX12);
                 break;
              case Encodation.TEXT:
                 context.writeCodeword(HighLevelEncoder.LATCH_TO_TEXT);
                 break;
              case Encodation.EDIFACT:
                 context.writeCodeword(HighLevelEncoder.LATCH_TO_EDIFACT);
                 break;
              case Encodation.ASCII:
                 break;
              default:
                 throw new InvalidOperationException("Illegal mode: " + encodingMode);
           }
           while (context.HasMoreCharacters)
           {
              encoders[encodingMode].encode(context);
              if (context.NewEncoding >= 0)
              {
                 encodingMode = context.NewEncoding;
                 context.resetEncoderSignal();
              }
           }
           int len = context.Codewords.Length;
           context.updateSymbolInfo();
           int capacity = context.SymbolInfo.dataCapacity;
           if (len < capacity)
           {
              if (encodingMode != Encodation.ASCII && encodingMode != Encodation.BASE256)
              {
                 context.writeCodeword('\u00fe'); //Unlatch (254)
              }
           }
           //Padding
           StringBuilder codewords = context.Codewords;
  
gt:          if (codewords.Length < capacity)