context: using System;
  using System.Text;
  
  using QRCodeImage = ThoughtWorks.QRCode.Codec.Data.QRCodeImage;
  using QRCodeSymbol = ThoughtWorks.QRCode.Codec.Data.QRCodeSymbol;
  using ReedSolomon = ThoughtWorks.QRCode.Codec.Ecc.ReedSolomon;
  using DecodingFailedException = ThoughtWorks.QRCode.ExceptionHandler.DecodingFailedException;
  using InvalidDataBlockException = ThoughtWorks.QRCode.ExceptionHandler.InvalidDataBlockException;
  using SymbolNotFoundException = ThoughtWorks.QRCode.ExceptionHandler.SymbolNotFoundException;
  using Point = ThoughtWorks.QRCode.Geom.Point;
  using QRCodeDataBlockReader = ThoughtWorks.QRCode.Codec.Reader.QRCodeDataBlockReader;
  using QRCodeImageReader = ThoughtWorks.QRCode.Codec.Reader.QRCodeImageReader;
  using DebugCanvas = ThoughtWorks.QRCode.Codec.Util.DebugCanvas;
  using DebugCanvasAdapter = ThoughtWorks.QRCode.Codec.Util.DebugCanvasAdapter;
  using QRCodeUtility = ThoughtWorks.QRCode.Codec.Util.QRCodeUtility;
  
  namespace ThoughtWorks.QRCode.Codec
  {
  	
  	public class QRCodeDecoder
  	{
          internal QRCodeSymbol qrCodeSymbol;
          internal int numTryDecode;
          internal System.Collections.ArrayList results;
          internal System.Collections.ArrayList lastResults = System.Collections.ArrayList.Synchronized(new System.Collections.ArrayList(10));
          internal static DebugCanvas canvas;
          internal QRCodeImageReader imageReader;
          internal int numLastCorrections;
          internal bool correctionSucceeded;
  
  		public static DebugCanvas Canvas
  		{
  			get
  			{
  				return QRCodeDecoder.canvas;
  			}
  			
  			set
  			{
  				QRCodeDecoder.canvas = value;
  			}
  			
  		}
  		virtual internal Point[] AdjustPoints
  		{
  			get
  			{
  				// note that adjusts affect dependently
  				// i.e. below means (0,0), (2,3), (3,4), (1,2), (2,1), (1,1), (-1,-1)
  				
  				
  				//		Point[] adjusts = {new Point(0,0), new Point(2,3), new Point(1,1), 
  				//				new Point(-2,-2), new Point(1,-1), new Point(-1,0), new Point(-2,-2)};
  				System.Collections.ArrayList adjustPoints = System.Collections.ArrayList.Synchronized(new System.Collections.ArrayList(10));
  				for (int d = 0; d < 4; d++)
  					adjustPoints.Add(new Point(1, 1));
  				int lastX = 0, lastY = 0;
  				for (int y = 0; y > - 4; y--)
  				{
  					for (int x = 0; x > - 4; x--)
  					{
  						if (x != y && ((x + y) % 2 == 0))
  						{
  							adjustPoints.Add(new Point(x - lastX, y - lastY));
  							lastX = x;
  							lastY = y;
  						}
  					}
  				}
  				Point[] adjusts = new Point[adjustPoints.Count];
  				for (int i = 0; i < adjusts.Length; i++)
  					adjusts[i] = (Point) adjustPoints[i];
  				return adjusts;
  			}			
  		}		
  				
  		internal class DecodeResult
  		{
              internal int numCorrections;
              internal bool correctionSucceeded;
              internal sbyte[] decodedBytes;
              private QRCodeDecoder enclosingInstance;
  
              public DecodeResult(QRCodeDecoder enclosingInstance, sbyte[] decodedBytes, int numErrors, bool correctionSucceeded)
              {
                  InitBlock(enclosingInstance);
                  this.decodedBytes = decodedBytes;
                  this.numCorrections = numErrors;
                  this.correctionSucceeded = correctionSucceeded;
              }
  
  			private void  InitBlock(QRCodeDecoder enclosingInstance)
  			{
  				this.enclosingInstance = enclosingInstance;
  			}
  
  			virtual public sbyte[] DecodedBytes
  			{
  				get
  				{
  					return decodedBytes;
  				}
  				
  			}
  			virtual public int NumErrors
  			{
  				get
  				{
  					return numCorrections;
  				}
  				
  			}
  			virtual public bool CorrectionSucceeded
  			{
  				get
  				{
  					return correctionSucceeded;
  				}
  				
  			}
  			public QRCodeDecoder Enclosing_Instance
  			{
  				get
  				{
  					return enclosingInstance;
  				}
  				
  			}
  			
  		}
  		
  		public QRCodeDecoder()
  		{
  			numTryDecode = 0;
  			results = System.Collections.ArrayList.Synchronized(new System.Collections.ArrayList(10));
  			QRCodeDecoder.canvas = new DebugCanvasAdapter();
  		}
  		
  		/*	public byte[] decode(QRCodeImage qrCodeImage) throws DecodingFailedException{
  		    canvas.println("Decoding started.");
  		    int[][] intImage = imageToIntArray(qrCodeImage);
  		    try {
  		    QRCodeImageReader reader = new QRCodeImageReader();
  		    qrCodeSymbol = reader.getQRCodeSymbol(intImage);
  		    } catch (SymbolNotFoundException e) {
  		    throw new DecodingFailedException(e.getMessage());
  		    }
  		    canvas.println("Created QRCode symbol.");
  		    canvas.println("Reading symbol.");
  		    canvas.println("Version: " + qrCodeSymbol.getVersionReference());		
  		    canvas.println("Mask pattern: " + qrCodeSymbol.getMaskPatternRefererAsString());
  		    int[] blocks = qrCodeSymbol.getBlocks();
  		    canvas.println("Correcting data errors.");
  		    int[] dataBlocks = correctDataBlocks(blocks);
  		    try {
  		    byte[] decodedByteArray = 
  		    getDecodedByteArray(dataBlocks, qrCodeSymbol.getVersion());
  		    canvas.println("Decoding finished.");
  		    return decodedByteArray;
  		    } catch (InvalidDataBlockException e) {
  		    throw new DecodingFailedException(e.getMessage());
  		    }
  		}*/
  		
  		public virtual sbyte[] decodeBytes(QRCodeImage qrCodeImage)
  		{
  			Point[] adjusts = AdjustPoints;
  			System.Collections.ArrayList results = System.Collections.ArrayList.Synchronized(new System.Collections.ArrayList(10));
  			while (numTryDecode < adjusts.Length)
  			{
  				try
  				{
  					DecodeResult result = decode(qrCodeImage, adjusts[numTryDecode]);
  					if (result.CorrectionSucceeded)
  					{
  						return result.DecodedBytes;
  					}
  					else
  					{
  						results.Add(result);
  						canvas.println("Decoding succeeded but could not correct");
  						canvas.println("all errors. Retrying..");
  					}
  				}
  				catch (DecodingFailedException dfe)
  				{
  					if (dfe.Message.IndexOf("Finder Pattern") >= 0)
  					throw dfe;
  				}
  				finally
  				{
  					numTryDecode += 1;
  				}
  			}
  			
  			if (results.Count == 0)
  				throw new DecodingFailedException("Give up decoding");
  			
  			int lowestErrorIndex = - 1;
  			int lowestError = System.Int32.MaxValue;
  			for (int i = 0; i < results.Count; i++)
  			{
  				DecodeResult result = (DecodeResult) results[i];
  				if (result.NumErrors < lowestError)
  				{
  					lowestError = result.NumErrors;
  					lowestErrorIndex = i;
  				}
  			}
  			canvas.println("All trials need for correct error");
  			canvas.println("Reporting #" + (lowestErrorIndex) + " that,");
  			canvas.println("corrected minimum errors (" + lowestError + ")");
  			
  			canvas.println("Decoding finished.");
  			return ((DecodeResult) results[lowestErrorIndex]).DecodedBytes;
  		}
  
          public virtual String decode(QRCodeImage qrCodeImage, Encoding encoding)
          {
              sbyte[] data = decodeBytes(qrCodeImage);
  
gt:             byte[] byteData = new byte[data.Length];