diff --git a/Source/GenCode128/Code128Code.cs b/Source/GenCode128/Code128Code.cs
index edc41ed..46247f9 100644
--- a/Source/GenCode128/Code128Code.cs
+++ b/Source/GenCode128/Code128Code.cs
@@ -1,20 +1,19 @@
 namespace GenCode128
 {
+    using System;
+
     /// 
     /// Static tools for determining codes for individual characters in the content
     /// 
     public static class Code128Code
     {
         private const int CShift = 98;
-
         private const int CCodeA = 101;
-
         private const int CCodeB = 100;
-
+        private const int CCodeC = 99;
         private const int CStartA = 103;
-
         private const int CStartB = 104;
-
+        private const int CStartC = 105;
         private const int CStop = 106;
         
         /// 
@@ -23,15 +22,14 @@ public static class Code128Code
         public enum CodeSetAllowed
         {
             CodeA,
-
             CodeB,
-
-            CodeAorB
+            CodeC,
+            CodeAorB,
+            CodeAorBorC
         }
 
         /// 
-        /// Get the Code128 code value(s) to represent an ASCII character, with 
-        /// optional look-ahead for length optimization
+        /// Get the Code128 code value(s) to represent an ASCII character
         /// 
         /// The ASCII value of the character to translate
         /// The next character in sequence (or -1 if none)
@@ -39,51 +37,120 @@ public enum CodeSetAllowed
         /// if the returned codes change that, then this value will be changed to reflect it
         /// An array of integers representing the codes that need to be output to produce the 
         /// given character
-        public static int[] CodesForChar(int charAscii, int lookAheadAscii, ref CodeSet currentCodeSet)
+        public static int[] CodesForChar(ref int[] charAscii, ref CodeSet currentCodeSet, ref int outerIndex)
         {
             int[] result;
             var shifter = -1;
+            var whatToConvert = -1;
+            CodeSet bestCodeSet;
+
+            // Let's find out which is the best set to use
+            bestCodeSet = BestFitSet(ref charAscii, currentCodeSet, ref shifter);
 
-            if (!CharCompatibleWithCodeset(charAscii, currentCodeSet))
+            // We`re not in the right CodeSet, so we should change it
+            if (currentCodeSet != bestCodeSet)
             {
-                // if we have a lookahead character AND if the next character is ALSO not compatible
-                if ((lookAheadAscii != -1) && !CharCompatibleWithCodeset(lookAheadAscii, currentCodeSet))
+                switch (bestCodeSet)
                 {
-                    // we need to switch code sets
-                    switch (currentCodeSet)
-                    {
-                        case CodeSet.CodeA:
-                            shifter = CCodeB;
-                            currentCodeSet = CodeSet.CodeB;
-                            break;
-                        case CodeSet.CodeB:
-                            shifter = CCodeA;
-                            currentCodeSet = CodeSet.CodeA;
-                            break;
-                    }
-                }
-                else
-                {
-                    // no need to switch code sets, a temporary SHIFT will suffice
-                    shifter = CShift;
+                    case CodeSet.CodeA:
+                        shifter = CCodeA;
+                        currentCodeSet = CodeSet.CodeA;
+                        break;
+                    case CodeSet.CodeB:
+                        shifter = CCodeB;
+                        currentCodeSet = CodeSet.CodeB;
+                        break;
+                    case CodeSet.CodeC:
+                        shifter = CCodeC;
+                        currentCodeSet = CodeSet.CodeC;
+                        break;
                 }
             }
 
+            // Check if is A/B or C and fill convert, but if it`s CodeSetC, we should code 2 at a time, instead of just one
+            switch (currentCodeSet)
+            {
+                case CodeSet.CodeA:
+                case CodeSet.CodeB:
+                    whatToConvert = charAscii[0];
+                    break;
+                case CodeSet.CodeC:
+                    whatToConvert = (Convert.ToInt32(Char.ConvertFromUtf32(charAscii[0])) * 10) + (Convert.ToInt32(Char.ConvertFromUtf32(charAscii[1])));
+                    outerIndex++;
+                    break;
+            }
+
             if (shifter != -1)
             {
                 result = new int[2];
                 result[0] = shifter;
-                result[1] = CodeValueForChar(charAscii);
+                result[1] = CodeValueForChar(whatToConvert, currentCodeSet);
             }
             else
             {
                 result = new int[1];
-                result[0] = CodeValueForChar(charAscii);
+                result[0] = CodeValueForChar(whatToConvert, currentCodeSet);
             }
 
             return result;
         }
 
+        /// 
+        /// Determines the best codeset to use, based on Code128 heuristics and optimizations
+        /// 
+        /// characters to check for
+        /// codeset context to test
+        /// a reference for the shifter
+        /// the best codeset to be used. Shift is also modified if necessary.
+        public static CodeSet BestFitSet(ref int[] charAscii, CodeSet currentCodeSet, ref int shifter)
+        {
+            bool bestA = false;
+            bool bestC = false;
+            bool commingFromC = false;
+            //bool bestB = false;
+
+            // Optimizing to use CodeSetC. If 6+ are numbers OR we're in the last 4 of the set, and all are numbers
+            // Care that we run from 0 to 5 -- Running through 6 and also checking >=3 which means the 4th ahead
+            if (currentCodeSet != CodeSet.CodeC)
+            {
+                bestC = true;
+                for (int i = 0; i < 6; i++)
+                {
+                    bestC = bestC && (CharCompatibleWithCodeset(charAscii[i], CodeSet.CodeC) ? ((charAscii[4] != -1 && charAscii[5] == -1) ? false : true) : ((charAscii[i] == -1 && i > 3) ? true : false));
+                    if (!bestC)
+                        break;
+                }
+            }
+            else
+            {
+                // if we're already in C, let's check if we can code at least 2 ascii
+                if (CharCompatibleWithCodeset(charAscii[0], CodeSet.CodeC) && CharCompatibleWithCodeset(charAscii[1], CodeSet.CodeC))
+                {
+                    bestC = true;
+                }
+                commingFromC = true;
+            }
+
+            if (CharCompatibleWithCodeset(charAscii[0], CodeSet.CodeA))
+            {
+                // if we have a lookahead character AND if the next character is ALSO not compatible
+                if ((charAscii[1] != -1) && (commingFromC || CharCompatibleWithCodeset(charAscii[1], CodeSet.CodeA)))
+                {
+                    // we need to switch code sets
+                    bestA = true;
+                }
+                else
+                {
+                    // no need to switch code sets, a temporary SHIFT will suffice
+                    shifter = CShift;
+                }
+            }
+
+            //Since we've already checked C and A, if both are False, we can only use CodeSetB
+            // Select the prefered one, putting CodeSetC as the first, since it's optimized
+            return bestC ? CodeSet.CodeC : (bestA ? CodeSet.CodeA : CodeSet.CodeB);
+        }
+
         /// 
         /// Tells us which codesets a given character value is allowed in
         /// 
@@ -91,13 +158,17 @@ public static int[] CodesForChar(int charAscii, int lookAheadAscii, ref CodeSet
         /// Which codeset(s) can be used to represent this character
         public static CodeSetAllowed CodesetAllowedForChar(int charAscii)
         {
-            if (charAscii >= 32 && charAscii <= 95)
+            if (charAscii >= 48 && charAscii <= 57)
+            {
+                return CodeSetAllowed.CodeC;
+            }
+            else if (charAscii >= 32 && charAscii <= 95)
             {
                 return CodeSetAllowed.CodeAorB;
             }
             else
             {
-                return charAscii < 32 ? CodeSetAllowed.CodeA : CodeSetAllowed.CodeB;
+                return (charAscii < 32) ? CodeSetAllowed.CodeA : CodeSetAllowed.CodeB;
             }
         }
 
@@ -110,7 +181,9 @@ public static CodeSetAllowed CodesetAllowedForChar(int charAscii)
         public static bool CharCompatibleWithCodeset(int charAscii, CodeSet currentCodeSet)
         {
             var csa = CodesetAllowedForChar(charAscii);
-            return csa == CodeSetAllowed.CodeAorB || (csa == CodeSetAllowed.CodeA && currentCodeSet == CodeSet.CodeA)
+            return (csa == CodeSetAllowed.CodeC && currentCodeSet == CodeSet.CodeC)
+                   || (csa == CodeSetAllowed.CodeAorB && (currentCodeSet == CodeSet.CodeA || currentCodeSet == CodeSet.CodeB))
+                   || (csa == CodeSetAllowed.CodeA && currentCodeSet == CodeSet.CodeA)
                    || (csa == CodeSetAllowed.CodeB && currentCodeSet == CodeSet.CodeB);
         }
 
@@ -119,9 +192,9 @@ public static bool CharCompatibleWithCodeset(int charAscii, CodeSet currentCodeS
         /// 
         /// character to convert
         /// code128 symbol value for the character
-        public static int CodeValueForChar(int charAscii)
+        public static int CodeValueForChar(int charAscii, CodeSet currentCodeSet)
         {
-            return charAscii >= 32 ? charAscii - 32 : charAscii + 64;
+            return currentCodeSet == CodeSet.CodeC ? charAscii : ((charAscii >= 32) ? charAscii - 32 : charAscii + 64);
         }
 
         /// 
@@ -131,7 +204,7 @@ public static int CodeValueForChar(int charAscii)
         /// The code128 code to start a barcode in that codeset
         public static int StartCodeForCodeSet(CodeSet cs)
         {
-            return cs == CodeSet.CodeA ? CStartA : CStartB;
+            return cs == CodeSet.CodeA ? CStartA : (cs == CodeSet.CodeB ? CStartB : CStartC);
         }
 
         /// 
diff --git a/Source/GenCode128/Code128Content.cs b/Source/GenCode128/Code128Content.cs
index 1ef32b6..8a98871 100644
--- a/Source/GenCode128/Code128Content.cs
+++ b/Source/GenCode128/Code128Content.cs
@@ -32,27 +32,44 @@ private int[] StringToCode128(string asciiData)
         {
             // turn the string into ascii byte data
             var asciiBytes = Encoding.ASCII.GetBytes(asciiData);
+            
+            // a support array, for our lookahead 
+            int[] nextchar = new int[6];
+
+            // a support array for us to choose which is the best starting code
+            Code128Code.CodeSetAllowed[] csa = new Code128Code.CodeSetAllowed[4];
 
             // decide which codeset to start with
-            var csa1 = asciiBytes.Length > 0
-                           ? Code128Code.CodesetAllowedForChar(asciiBytes[0])
-                           : Code128Code.CodeSetAllowed.CodeAorB;
-            var csa2 = asciiBytes.Length > 1
-                           ? Code128Code.CodesetAllowedForChar(asciiBytes[1])
-                           : Code128Code.CodeSetAllowed.CodeAorB;
-            var currentCodeSet = this.GetBestStartSet(csa1, csa2);
+
+            csa[0] = asciiBytes.Length > 0
+                                        ? Code128Code.CodesetAllowedForChar(asciiBytes[0])
+                                        : Code128Code.CodeSetAllowed.CodeAorBorC;
+            csa[1] = asciiBytes.Length > 1
+                                        ? Code128Code.CodesetAllowedForChar(asciiBytes[1])
+                                        : Code128Code.CodeSetAllowed.CodeAorBorC;
+            csa[2] = asciiBytes.Length > 2
+                                        ? Code128Code.CodesetAllowedForChar(asciiBytes[2])
+                                        : Code128Code.CodeSetAllowed.CodeAorBorC;
+            csa[3] = asciiBytes.Length > 3
+                                        ? Code128Code.CodesetAllowedForChar(asciiBytes[3])
+                                        : Code128Code.CodeSetAllowed.CodeAorBorC;
+            var currentCodeSet = this.GetBestStartSet(csa);
 
             // set up the beginning of the barcode
             // assume no codeset changes, account for start, checksum, and stop
             var codes = new ArrayList(asciiBytes.Length + 3) { Code128Code.StartCodeForCodeSet(currentCodeSet) };
-            
-            // add the codes for each character in the string
+
+            // add the codes for each character in the string, checking the 6 char lookahead
             for (var i = 0; i < asciiBytes.Length; i++)
             {
-                int thischar = asciiBytes[i];
-                var nextchar = asciiBytes.Length > i + 1 ? asciiBytes[i + 1] : -1;
+                nextchar[0] = asciiBytes[i];
+                nextchar[1] = asciiBytes.Length > (i + 1) ? asciiBytes[i + 1] : -1;
+                nextchar[2] = asciiBytes.Length > (i + 2) ? asciiBytes[i + 2] : -1;
+                nextchar[3] = asciiBytes.Length > (i + 3) ? asciiBytes[i + 3] : -1;
+                nextchar[4] = asciiBytes.Length > (i + 4) ? asciiBytes[i + 4] : -1;
+                nextchar[5] = asciiBytes.Length > (i + 5) ? asciiBytes[i + 5] : -1;
 
-                codes.AddRange(Code128Code.CodesForChar(thischar, nextchar, ref currentCodeSet));
+                codes.AddRange(Code128Code.CodesForChar(ref nextchar, ref currentCodeSet, ref i));
             }
 
             // calculate the check digit
@@ -71,22 +88,36 @@ private int[] StringToCode128(string asciiData)
         }
 
         /// 
-        /// Determines the best starting code set based on the the first two 
+        /// Determines the best starting code set based on the the
         /// characters of the string to be encoded
         /// 
-        /// First character of input string
-        /// Second character of input string
+        /// First 4 characters of input string
         /// The codeset determined to be best to start with
-        private CodeSet GetBestStartSet(Code128Code.CodeSetAllowed csa1, Code128Code.CodeSetAllowed csa2)
+        private CodeSet GetBestStartSet(Code128Code.CodeSetAllowed[] initChars)
         {
-            var vote = 0;
+            int vote = 0;
+            int votec = 0;
 
-            vote += csa1 == Code128Code.CodeSetAllowed.CodeA ? 1 : 0;
-            vote += csa1 == Code128Code.CodeSetAllowed.CodeB ? -1 : 0;
-            vote += csa2 == Code128Code.CodeSetAllowed.CodeA ? 1 : 0;
-            vote += csa2 == Code128Code.CodeSetAllowed.CodeB ? -1 : 0;
+            for (int i = 0; i < 4; i++)
+            {
+                switch (initChars[i])
+                {
+                    case Code128Code.CodeSetAllowed.CodeA:
+                        vote += 1;
+                        break;
+                    case Code128Code.CodeSetAllowed.CodeB:
+                        vote -= 1;
+                        break;
+                    case Code128Code.CodeSetAllowed.CodeC:
+                        votec += 2;
+                        break;
+                        /*default:
+                            break;*/
+                }
+            }
 
-            return vote > 0 ? CodeSet.CodeA : CodeSet.CodeB; // ties go to codeB due to my own prejudices
+            //Optimizing: 4+ or only 2 characters codeC. Otherwise, vote for codeA or codeB. Ties go to codeB due to my own prejudices
+            return (votec == 8 || (votec == 4 && vote == 0)) ? CodeSet.CodeC : ((vote > 0) ? CodeSet.CodeA : CodeSet.CodeB);
         }
     }
 }
diff --git a/Source/GenCode128/Code128Rendering.cs b/Source/GenCode128/Code128Rendering.cs
index 0dd7fc1..20944dd 100644
--- a/Source/GenCode128/Code128Rendering.cs
+++ b/Source/GenCode128/Code128Rendering.cs
@@ -15,6 +15,9 @@ public static class Code128Rendering
         // however, the last one -- STOP -- has 7. The cost of the
         // extra integers is trivial, and this lets the code flow
         // much more elegantly
+        // The code representes 1s and 0s, that always change and,
+        // this way, we can representa all with 6 elements.
+        // Reference: http://www.barcodeisland.com/code128.phtml
         private static readonly int[,] CPatterns =
                                                     {
                                                      { 2, 1, 2, 2, 2, 2, 0, 0 }, // 0
diff --git a/Source/GenCode128/CodeSet.cs b/Source/GenCode128/CodeSet.cs
index 07c7bd1..e56bbcc 100644
--- a/Source/GenCode128/CodeSet.cs
+++ b/Source/GenCode128/CodeSet.cs
@@ -3,7 +3,7 @@ namespace GenCode128
     public enum CodeSet
     {
         CodeA,
-        CodeB
-        //// CodeC   // not supported
+        CodeB,
+        CodeC
     }
 }
\ No newline at end of file