// 
// Copyright 2016 Agencia Estatal de Administración Tibutaria
//
// Licencia con arreglo a la EUPL, Versión 1.1 o -en cuanto
// sean aprobadas por la Comisión Europea- versiones
// posteriores de la EUPL (la «Licencia»);
// Solo podrá usarse esta obra si se respeta la Licencia.
// Puede obtenerse una copia de la Licencia en:
//  
// https://joinup.ec.europa.eu/software/page/eupl
//  
// Salvo cuando lo exija la legislación aplicable o se acuerde
// por escrito, el programa distribuido con arreglo a la
// Licencia se distribuye «TAL CUAL», SIN GARANTÍAS NI CONDICIONES
// DE NINGÚN TIPO, ni expresasni implícitas.
//
// Véase la Licencia en el idioma concreto que rige los permisos y 
// limitaciones que establece la Licencia.
// 

using System;
using System.Collections.Generic;
using System.Text;
using System.IO;

namespace ateneo.utiles
{
    public class AdlerChecksum
    {
        // parameters
        #region
        public const uint AdlerBase = 0xFFF1;
        public const uint AdlerStart = 0x0001;
        public const uint AdlerBuff = 0x1000;
        private uint m_unChecksumValue = 0;
        #endregion

        public uint ChecksumValue {
            get {
                return m_unChecksumValue;
            }
        }

        public AdlerChecksum() {
            m_unChecksumValue = AdlerStart;
        }

        public bool update(byte[] bytesBuff) {
            if (!MakeForBuff(bytesBuff, m_unChecksumValue)) {
                m_unChecksumValue = 0;
                return false;
            }
            return true;
        }

        public bool MakeForBuff(byte[] bytesBuff, uint unAdlerCheckSum) {
            if (Object.Equals(bytesBuff, null)) {
                m_unChecksumValue = 0;
                return false;
            }
            int nSize = bytesBuff.GetLength(0);
            if (nSize == 0) {
                m_unChecksumValue = 0;
                return false;
            }
            uint unSum1 = unAdlerCheckSum & 0xFFFF;
            uint unSum2 = (unAdlerCheckSum >> 16) & 0xFFFF;
            for (int i = 0; i < nSize; i++) {
                unSum1 = (unSum1 + bytesBuff[i]) % AdlerBase;
                unSum2 = (unSum1 + unSum2) % AdlerBase;
            }
            m_unChecksumValue = (unSum2 << 16) + unSum1;
            return true;
        }
        public bool MakeForBuff(byte[] bytesBuff) {
            return MakeForBuff(bytesBuff, AdlerStart);
        }

        public bool MakeForFile(string sPath) {
            FileStream fs = null;
            try {
                if (!File.Exists(sPath)) {
                    m_unChecksumValue = 0;
                    return false;
                }
                fs = new FileStream(sPath, FileMode.Open, FileAccess.Read);
                if (Object.Equals(fs, null)) {
                    m_unChecksumValue = 0;
                    return false;
                }
                if (fs.Length == 0) {
                    m_unChecksumValue = 0;
                    return false;
                }
                m_unChecksumValue = AdlerStart;
                byte[] bytesBuff = new byte[AdlerBuff];
                while (true) {
                    int leidos = fs.Read(bytesBuff, 0, (int)AdlerBuff);
                    if (leidos == 0) break;
                    if (!MakeForBuff(bytesBuff, m_unChecksumValue)) {
                        m_unChecksumValue = 0;
                        return false;
                    }
                }
            } catch {
                m_unChecksumValue = 0;
                return false;
            } finally {
                fs.Close();
            }
            return true;
        }
    }
}
