/// <summary>
        /// processing MT940 file
        /// </summary>
        /// <param name="filename"></param>
        public void ProcessFile(string filename)
        {
            Console.WriteLine("Read file " + filename);
            Int32 LineCounter = 0;

            try
            {
                StreamReader reader = new StreamReader(filename, Encoding.GetEncoding(1252));
                string fileContent = reader.ReadToEnd();
                reader.Close();

                string swiftTag = "";
                string swiftData = "";
                statements = new List <TStatement>();
                currentStatement = null;

                while (fileContent.Length > 0)
                {
                    string line = ReadLine(ref fileContent);
                    LineCounter++;

                    if ((line.Length > 0) && (!line.StartsWith("-")))
                    {
                        // a swift chunk starts with a swiftTag, which is between colons
                        if (line.StartsWith(":"))
                        {
                            // process previously read swift chunk
                            if (swiftTag.Length > 0)
                            {
                                // Console.WriteLine(" Tag " + swiftTag + " Data " + swiftData);
                                HandleSwiftData(swiftTag, swiftData);
                            }

                            int posColon = line.IndexOf(":", 2);
                            swiftTag = line.Substring(1, posColon - 1);
                            swiftData = line.Substring(posColon + 1);
                        }
                        else
                        {
                            // the swift chunk is spread over several lines
                            swiftData = swiftData + line;
                        }
                    }
                }

                if (swiftTag.Length > 0)
                {
                    HandleSwiftData(swiftTag, swiftData);
                }
            }
            catch (Exception e)
            {
                throw new Exception(
                    "problem with file " + filename + "; line: " + LineCounter.ToString() + "; " + e.Message + Environment.NewLine + e.StackTrace);
            }
        }
        private void HandleSwiftData(string swiftTag, string swiftData)
        {
            if (currentStatement != null)
            {
                currentStatement.lines.Add(new TLine(swiftTag, swiftData));
            }

            if (swiftTag == "OS")
            {
                // ignore
            }
            else if (swiftTag == "20")
            {
                // 20 is used for each "page" of the statement; but we want to put all transactions together
                // the whole statement closes with 62F
                if (currentStatement == null)
                {
                    currentStatement = new TStatement();
                    currentStatement.lines.Add(new TLine(swiftTag, swiftData));
                }
            }
            else if (swiftTag == "25")
            {
                int posSlash = swiftData.IndexOf("/");
                currentStatement.bankCode = swiftData.Substring(0, posSlash);
                currentStatement.accountCode = WithoutLeadingZeros(swiftData.Substring(posSlash + 1));
            }
            else if (swiftTag.StartsWith("60"))
            {
                // 60M is the start balance on each page of the statement.
                // 60F is the start balance of the whole statement.

                // first character is D or C
                int DebitCreditIndicator = (swiftData[0] == 'D' ? -1 : +1);

                // next 6 characters: YYMMDD
                // next 3 characters: currency
                // last characters: balance with comma for decimal point
                currentStatement.currency = swiftData.Substring(7, 3);
                decimal balance = DebitCreditIndicator * Convert.ToDecimal(swiftData.Substring(10).Replace(",",
                        Thread.CurrentThread.CurrentCulture.NumberFormat.CurrencyDecimalSeparator));

                // we only want to use the first start balance
                if (swiftTag == "60F")
                {
                    currentStatement.startBalance = balance;
                    currentStatement.endBalance = balance;
                }
                else
                {
                    // check if the balance inside the statement is ok
                    // ie it fits the balance of the previous page
                    if (Convert.ToDecimal(Math.Round(currentStatement.endBalance, 2)) != Convert.ToDecimal(balance))
                    {
                        throw new Exception("start balance does not match current balance");
                    }
                }
            }
            else if (swiftTag == "28C")
            {
                // this contains the number of the statement and the number of the page
                // only use for first page
                if (currentStatement.transactions.Count == 0)
                {
                    if (swiftData.IndexOf("/") != -1)
                    {
                        currentStatement.id = swiftData.Substring(0, swiftData.IndexOf("/"));
                    }
                    else
                    {
                        // realtime statement. do not use statement number 0, because Sparkasse has 0/1 for valid statements
                        currentStatement.id = string.Empty;
                    }
                }
            }
            else if (swiftTag == "61")
            {
                TTransaction transaction = new TTransaction();

                // valuta date (YYMMDD)
                try
                {
                    transaction.valueDate = new DateTime(2000 + Convert.ToInt32(swiftData.Substring(0, 2)),
                        Convert.ToInt32(swiftData.Substring(2, 2)),
                        Convert.ToInt32(swiftData.Substring(4, 2)));
                }
                catch (ArgumentOutOfRangeException)
                {
                    // we have had the situation in the bank file with a date 30 Feb 2010.
                    // probably because the instruction by the donor is to transfer the money on the 30 day each month
                    // use the last day of the month
                    int year = 2000 + Convert.ToInt32(swiftData.Substring(0, 2));
                    int month = Convert.ToInt32(swiftData.Substring(2, 2));
                    int day = DateTime.DaysInMonth(year, month);
                    transaction.valueDate = new DateTime(year, month, day);
                }

                swiftData = swiftData.Substring(6);

                if (char.IsDigit(swiftData[0]))
                {
                    // posting date (MMDD)
                    transaction.inputDate = new DateTime(transaction.valueDate.Year,
                        Convert.ToInt32(swiftData.Substring(0, 2)),
                        Convert.ToInt32(swiftData.Substring(2, 2)));
                    swiftData = swiftData.Substring(4);
                }
                else
                {
                    transaction.inputDate = transaction.valueDate;
                }

                // debit or credit, or storno debit or credit
                int debitCreditIndicator = 0;

                if (swiftData[0] == 'R')
                {
                    // storno means: reverse the debit credit flag
                    debitCreditIndicator = (swiftData[1] == 'D' ? 1 : -1);

                    swiftData = swiftData.Substring(2);
                }
                else
                {
                    debitCreditIndicator = (swiftData[0] == 'D' ? -1 : 1);
                    swiftData = swiftData.Substring(1);
                }

                // sometimes there is something about currency
                if (Char.IsLetter(swiftData[0]))
                {
                    // just skip it for the moment
                    swiftData = swiftData.Substring(1);
                }

                // the amount, finishing with N
                transaction.amount =
                    debitCreditIndicator * Convert.ToDecimal(swiftData.Substring(0, swiftData.IndexOf("N")).Replace(",",
                            Thread.CurrentThread.CurrentCulture.NumberFormat.CurrencyDecimalSeparator));
                currentStatement.endBalance += transaction.amount;
                swiftData = swiftData.Substring(swiftData.IndexOf("N"));

                // Geschaeftsvorfallcode
                // transaction.typecode = swiftData.Substring(1, 3);
                swiftData = swiftData.Substring(4);

                // the following sub fields are ignored
                // optional: customer reference; ends with //
                // optional: bank reference; ends with CR/LF
                // something else about original currency and transaction fees

                currentStatement.transactions.Add(transaction);
            }
            else if (swiftTag == "86")
            {
                TTransaction transaction = currentStatement.transactions[currentStatement.transactions.Count - 1];

                // Geschaeftsvorfallcode
                transaction.typecode = swiftData.Substring(0, 3);
                swiftData = swiftData.Substring(3);
                char separator = swiftData[0];
                swiftData = swiftData.Substring(1);
                string[] elements = swiftData.Split(new char[] { separator });

                foreach (string element in elements)
                {
                    int key = 0;
                    string value = element;

                    try
                    {
                        key = Convert.ToInt32(element.Substring(0, 2));
                        value = element.Substring(2);
                    }
                    catch (Exception)
                    {
                        // if there is a question mark in the description, then we get here
                    }

                    if (key == 0)
                    {
                        // Buchungstext
                        transaction.text = value;
                    }
                    else if (key == 10)
                    {
                        // Primanotennummer; ignore at the moment
                    }
                    else if ((key >= 11) && (key <= 19))
                    {
                        // ignore, unknown meaning
                    }
                    else if ((key >= 20) && (key <= 29))
                    {
                        // do not insert a space between description lines
                        transaction.description += value;
                    }
                    else if (key == 30)
                    {
                        transaction.bankCode = value;
                    }
                    else if (key == 31)
                    {
                        // could use WithoutLeadingZeros, but then this must be stored in p_banking_details also without leading zeros
                        // which is not the case at the moment, and would increase complexity of sql queries
                        transaction.accountCode = value;
                    }
                    else if ((key == 32) || (key == 33))
                    {
                        transaction.partnerName += value;
                    }
                    else if (key == 34)
                    {
                        // Textschlüsselergänzung; ignore
                    }
                    else if ((key >= 60) && (key <= 63))
                    {
                        transaction.description += value;
                    }
                    else
                    {
                        throw new Exception("unknown key " + key.ToString());
                    }
                }
            }
            else if (swiftTag.StartsWith("62"))
            {
                // 62M: finish page
                // 62F: finish statement
                int debitCreditIndicator = (swiftData[0] == 'D' ? -1 : 1);
                swiftData = swiftData.Substring(1);

                // posting date YYMMDD
                DateTime postingDate = new DateTime(2000 + Convert.ToInt32(swiftData.Substring(0, 2)),
                    Convert.ToInt32(swiftData.Substring(2, 2)),
                    Convert.ToInt32(swiftData.Substring(4, 2)));
                swiftData = swiftData.Substring(6);

                // currency
                swiftData = swiftData.Substring(3);

                // sometimes, this line is the last line, and it has -NULNULNUL at the end
                if (swiftData.Contains("-\0"))
                {
                    swiftData = swiftData.Substring(0, swiftData.IndexOf("-\0"));
                }

                // end balance
                decimal shouldBeBalance = debitCreditIndicator * Convert.ToDecimal(swiftData.Replace(",",
                        Thread.CurrentThread.CurrentCulture.NumberFormat.CurrencyDecimalSeparator));

                currentStatement.endBalance = Math.Round(currentStatement.endBalance, 2);

                if (Convert.ToDecimal(Math.Round(currentStatement.endBalance, 2)) != Convert.ToDecimal(shouldBeBalance))
                {
                    throw new Exception("end balance does not match" +
                        " last transaction was: " + currentStatement.transactions[currentStatement.transactions.Count - 1].partnerName +
                        " balance is: " + currentStatement.endBalance.ToString() +
                        " but should be: " + shouldBeBalance.ToString());
                }

                if (swiftTag == "62F")
                {
                    currentStatement.date = postingDate;
                    statements.Add(currentStatement);
                    currentStatement = null;
                }
            }
            else if (swiftTag == "64")
            {
                // valutensaldo; ignore
            }
            else if (swiftTag == "65")
            {
                // future valutensaldo; ignore
            }
            else
            {
                Console.WriteLine("swiftTag " + swiftTag + " is unknown");
            }
        }
        /// <summary>
        /// this is useful to save an MT940 file after splitting by date
        /// </summary>
        /// <param name="AFilename"></param>
        /// <param name="AStmt"></param>
        public static void DumpMT940File(string AFilename, TStatement AStmt)
        {
            StreamWriter sw = new StreamWriter(AFilename, false, Encoding.Default);

            foreach (TLine line in AStmt.lines)
            {
                sw.WriteLine(":" + line.swiftTag + ":" + line.swiftData);
            }

            sw.Close();
        }