using System;
//using System.Collections.Generic;
//using System.Linq;
using System.IO;                      // FileStream, FileMode, FileAccess
using System.Runtime.InteropServices; // GCHandle, GCHandleType, Marshal, ComImport, Guid, InterfaceType, In, Out
using System.Text;                    // Encoding

namespace nodokaGuiEdit
{
    // from http://tech.nitoyon.com/ja/blog/2012/03/07/detectinputcodepage-in-cs/
    class detectencode
    {

        public Encoding DetectFileEncoding(string srcFile)
        {
            Encoding encoding = DetectEncoding(GetFileAsByteArray(srcFile)); 
            return encoding;
        }

        // 指定されたファイルを開いてbyte配列で返す。
        // todo fileが無かった場合の処理を追加するか、呼び側で処理すること。
        private byte[] GetFileAsByteArray(string path)
        {
            using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read))
            {
                byte[] bytes = new byte[fs.Length];
                fs.Read(bytes, 0, bytes.Length);
                return bytes;
            }
        }

        // 指定されたbyte配列から、文字エンコードを返す。
        private Encoding DetectEncoding(byte[] bytes)
        {
            IMultiLanguage2 lang = (IMultiLanguage2)new MultiLanguage();
            int len = bytes.Length;
            DetectEncodingInfo info = new DetectEncodingInfo();
            int scores = 1;

            // bytes to IntPtr
            GCHandle handle = GCHandle.Alloc(bytes, GCHandleType.Pinned);
            IntPtr pbytes = Marshal.UnsafeAddrOfPinnedArrayElement(bytes, 0);

            try
            {
                lang.DetectInputCodepage(0, 0, pbytes, ref len, out info, ref scores);
            }
            finally
            {
                if (handle.IsAllocated)
                    handle.Free();
            }

            return Encoding.GetEncoding((int)info.nCodePage);
        }

#pragma warning disable 0649
        public struct DetectEncodingInfo
        {
            public UInt32 nLangID;
            public UInt32 nCodePage;
            public Int32 nDocPercent;
            public Int32 nConfidence;
        };
#pragma warning restore 0649

        [ComImport, Guid("275c23e2-3747-11d0-9fea-00aa003f8646")]
        public class MultiLanguage
        {
        }

        [Guid("DCCFC164-2B38-11D2-B7EC-00C04F8F5D9A"),
        InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
        public interface IMultiLanguage2
        {
            void GetNumberOfCodePageInfo();
            void GetCodePageInfo();
            void GetFamilyCodePage();
            void EnumCodePages();
            void GetCharsetInfo();
            void IsConvertible();
            void ConvertString();
            void ConvertStringToUnicode();
            void ConvertStringFromUnicode();
            void ConvertStringReset();
            void GetRfc1766FromLcid();
            void GetLcidFromRfc1766();
            void EnumRfc1766();
            void GetRfc1766Info();
            void CreateConvertCharset();
            void ConvertStringInIStream();
            void ConvertStringToUnicodeEx();
            void ConvertStringFromUnicodeEx();
            void DetectCodepageInIStream();
            void DetectInputCodepage(
                [In] UInt32 dwFlag,
                [In] UInt32 dwPrefWinCodePage,
                [In] IntPtr pSrcStr,
                [In, Out] ref Int32 pcSrcSize,
                [Out] out DetectEncodingInfo lpEncoding,
                [In, Out] ref Int32 pnScores);
            void ValidateCodePage();
            void GetCodePageDescription();
            void IsCodePageInstallable();
            void SetMimeDBSource();
            void GetNumberOfScripts();
            void EnumScripts();
            void ValidateCodePageEx();
        }
    }
}
