private static CodeMemberMethod BuildReadMethod(CsvSpreadSheet sheet)
    {
        CodeMemberMethod readMethod = new CodeMemberMethod();

        readMethod.Attributes = MemberAttributes.Public | MemberAttributes.Final | MemberAttributes.Static;
        readMethod.Name       = "Read";
        readMethod.Parameters.Add(new CodeParameterDeclarationExpression(typeof(string), "fileName"));

        // CsvSpreadSheet sheet = new CsvSpreadSheet(fileName);
        CodeMethodInvokeExpression callClearData = new  CodeMethodInvokeExpression(new CodeVariableReferenceExpression("Data"), "Clear");

        readMethod.Statements.Add(callClearData);

        CodeVariableDeclarationStatement declaraSheet = new CodeVariableDeclarationStatement(typeof(CsvSpreadSheet), "sheet");

        declaraSheet.InitExpression = new CodeObjectCreateExpression(typeof(CsvSpreadSheet), new CodeExpression[] { new CodeVariableReferenceExpression("fileName"), new CodePrimitiveExpression(true) });
        readMethod.Statements.Add(declaraSheet);

        // for statment
        CodeIterationStatement forStatement = new CodeIterationStatement();

        forStatement.InitStatement = new CodeVariableDeclarationStatement(typeof(int), "i", new CodePrimitiveExpression(0));

        forStatement.TestExpression = new CodeBinaryOperatorExpression(new CodeVariableReferenceExpression("i"), CodeBinaryOperatorType.LessThan, new CodeSnippetExpression("sheet.Records.Count"));

        forStatement.IncrementStatement = new CodeAssignStatement(new CodeVariableReferenceExpression("i"), new CodeBinaryOperatorExpression(
                                                                      new CodeVariableReferenceExpression("i"), CodeBinaryOperatorType.Add, new CodePrimitiveExpression(1)));

        forStatement.Statements.Add(new CodeVariableDeclarationStatement(JumpCsvEditorHelper.GetCsvDataStructName(sheet.CsvFileName), "record", new CodeObjectCreateExpression(JumpCsvEditorHelper.GetCsvDataStructName(sheet.CsvFileName), new CodeExpression[] {})));
        foreach (CodeStatement t in BuildReadStatements(sheet))
        {
            forStatement.Statements.Add(t);
        }

        // add new record to list or dictionary
        if (sheet.Kind == CsvSpreadSheet.EKind.DicRecord)
        {
            CodeVariableDeclarationStatement keyValueDeclaration = new CodeVariableDeclarationStatement(typeof(int), "keyValue");
            keyValueDeclaration.InitExpression = new CodeSnippetExpression(@"sheet.GetRecord(i).KeyValue");
            forStatement.Statements.Add(keyValueDeclaration);
            forStatement.Statements.Add(new CodeSnippetExpression(@"Data.Add(keyValue, record);"));
        }
        else if (sheet.Kind == CsvSpreadSheet.EKind.ListRecord)
        {
            forStatement.Statements.Add(new CodeSnippetExpression(@"Data.Add(record)"));
        }

        readMethod.Statements.Add(forStatement);
        return(readMethod);
    }
    private static CodeMemberField BuildRecordValue2IdDictinaroy(CsvSpreadSheet sheet)
    {
        CodeMemberField dicData = new CodeMemberField("readonly Dictionary<string, int>", "IdRecordValue");

        dicData.Attributes = MemberAttributes.Static | MemberAttributes.Public;
        StringBuilder intiString = new StringBuilder(1024);

        intiString.Append("new Dictionary<string, int>() {");
        foreach (var t in sheet.Records)
        {
            intiString.Append(string.Format("{2}            {{{0,-30}, {1,-3}}},", "\"" + t.KeyName + "\"", t.KeyValue, Environment.NewLine));
        }
        intiString.Append(Environment.NewLine + "        }");

        dicData.InitExpression = new CodeSnippetExpression(intiString.ToString());
        return(dicData);
    }
    private static CodeStatement[] BuildReadStatements(CsvSpreadSheet sheet)
    {
        List <CsvSpreadSheet.HeaderRecord> headerList = sheet.Header;

        CodeStatement[] result = new CodeStatement[headerList.Count];
        for (int i = 0; i < headerList.Count; i++)
        {
            if (headerList[i].Name == "_ID")
            {
                CodeSnippetStatement snippet = new CodeSnippetStatement("                record._ID = CsvValueConverter.ReadValueDicValue(sheet, i, \"_VALUE\");");
                result[i] = snippet;
            }
            else
            {
                CodeAssignStatement assign = new CodeAssignStatement();
                assign.Left  = new CodeFieldReferenceExpression(new CodeVariableReferenceExpression("record"), headerList[i].Name);
                assign.Right = new CodeMethodInvokeExpression(new CodeVariableReferenceExpression("CsvValueConverter"), CsvHelper.GetReadColumnFunctionName(headerList[i].TypeLiteral),
                                                              new CodeExpression[] { new CodeVariableReferenceExpression("sheet"), new CodeVariableReferenceExpression("i"), new CodePrimitiveExpression(headerList[i].Name) });
                result[i] = assign;
            }
        }
        return(result);
    }
    public static string CreateCsvDataClassSourceFile2(CsvSpreadSheet sheet)
    {
        CodeCompileUnit codeUnit         = new CodeCompileUnit();
        CodeNamespace   jumpCsvNamespace = new CodeNamespace("JumpCSV");

        // add import directives used by the namespace.
        jumpCsvNamespace.Imports.Add(new CodeNamespaceImport("System"));
        jumpCsvNamespace.Imports.Add(new CodeNamespaceImport("System.IO"));
        jumpCsvNamespace.Imports.Add(new CodeNamespaceImport("System.Collections"));
        jumpCsvNamespace.Imports.Add(new CodeNamespaceImport("System.Collections.Generic"));
        jumpCsvNamespace.Imports.Add(new CodeNamespaceImport("System.Runtime.Serialization.Formatters.Binary"));
        jumpCsvNamespace.Imports.Add(new CodeNamespaceImport("UnityEngine"));

        codeUnit.Namespaces.Add(jumpCsvNamespace);
        jumpCsvNamespace.Types.Add(BuildCsvRecordStructDeclaration(sheet));
        jumpCsvNamespace.Types.Add(BuildCsvDataClassDeclarationLocalization(sheet));

        string csFileName = JumpCsvEditorHelper.PathCombine(Application.temporaryCachePath,
                                                            JumpCsvEditorHelper.GetCsvDataClassName(sheet.CsvFileName) + ".cs");

        GenerateCSharpCode(csFileName, codeUnit);
        return(csFileName);
    }
    private static CodeTypeDeclaration BuildCsvDataClassDeclaration(CsvSpreadSheet sheet)
    {
        string className = JumpCsvEditorHelper.GetCsvDataClassName(sheet.CsvFileName);
        CodeTypeDeclaration classType = new CodeTypeDeclaration(className);

        classType.IsClass        = true;
        classType.TypeAttributes = TypeAttributes.Public;

        if (sheet.Kind == CsvSpreadSheet.EKind.DicRecord)
        {
            classType.Members.Add(new CodeSnippetTypeMember(
                                      string.Format("public static Dictionary<{0}, {1}> Data = new Dictionary<{0}, {1}>();", "int", JumpCsvEditorHelper.GetCsvDataStructName(sheet.CsvFileName))));

            classType.Members.Add(new CodeSnippetTypeMember(
                                      string.Format("public static {0} GetRecord(int id)", JumpCsvEditorHelper.GetCsvDataStructName(sheet.CsvFileName))));
            classType.Members.Add(new CodeSnippetTypeMember(
                                      @"{ 
        if(Data.ContainsKey(id)) {
                return Data[id];
            }
            else {
                throw new Exception(""Can not find record by id "" + id);
            }
        }"));

            classType.Members.Add(new CodeSnippetTypeMember(
                                      @"public static void Serialize(string filename) {
            BinaryFormatter formatter = new BinaryFormatter();
            Stream stream = new FileStream(filename, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None);
            MemoryStream mstream = new MemoryStream();
            formatter.Serialize(mstream, Data);
            byte[] mbyte = mstream.ToArray();
            byte[] tmp = new byte[mbyte.Length];
            CsvHelper.Encode(mbyte, 0, tmp, 0, tmp.Length, ASCIIEncoding.ASCII.GetBytes(""ABCDEFG2""));
            stream.Write(tmp, 0, tmp.Length);
            mstream.Close();
            stream.Close();
        }"));


            classType.Members.Add(new CodeSnippetTypeMember(
                                      @"public static void Deserialize(string filename, bool isAssetBundle = false) {
            TextAsset textAsset = null;
            if(isAssetBundle && AssetBundleMgr.ContainsFile(filename, ""bytes"")) {
                textAsset = AssetBundleMgr.Load(filename, ""bytes"") as TextAsset;
            }
            else {
                textAsset = Resources.Load(filename) as TextAsset;
            }
            BinaryFormatter formatter = new BinaryFormatter();
            MemoryStream mstream = new MemoryStream();
            byte[] tmp = new byte[textAsset.bytes.Length];
            CsvHelper.Encode(textAsset.bytes, 0, tmp, 0, tmp.Length, ASCIIEncoding.ASCII.GetBytes(""ABCDEFG2""));
            mstream.Write(tmp, 0, tmp.Length);
            mstream.Position = 0;
            " +
                                      string.Format("Data = formatter.Deserialize(mstream) as Dictionary<int, {0}>;", JumpCsvEditorHelper.GetCsvDataStructName(sheet.CsvFileName))));

            classType.Members.Add(new CodeSnippetTypeMember(
                                      @"    mstream.Close();    
        }"));
            classType.Members.Add(BuildRecordIdValueDictinaroy(sheet));
            classType.Members.Add(BuildRecordValue2IdDictinaroy(sheet));
            // add record type value dictionary
        }
        else if (sheet.Kind == CsvSpreadSheet.EKind.ListRecord)
        {
            classType.Members.Add(new CodeSnippetTypeMember(string.Format("public static List<{0}> Data = new List<{0}>();", JumpCsvEditorHelper.GetCsvDataStructName(sheet.CsvFileName))));
            classType.Members.Add(new CodeSnippetTypeMember(
                                      string.Format("public static {0} GetRecord(int index)", JumpCsvEditorHelper.GetCsvDataStructName(sheet.CsvFileName))));
            classType.Members.Add(new CodeSnippetTypeMember(
                                      @"{ 
        if(Data.Count >= index) {
                return Data[index];
            }
            else {
                throw new Exception(""Can not find record by index "" + index);
            }
        }"));

            classType.Members.Add(new CodeSnippetTypeMember(
                                      @"public static void Serialize(string filename) {
            BinaryFormatter formatter = new BinaryFormatter();
            Stream stream = new FileStream(filename, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None);
            MemoryStream mstream = new MemoryStream();
            formatter.Serialize(mstream, Data);
            byte[] mbyte = mstream.ToArray();
            byte[] tmp = new byte[mbyte.Length];
            CsvHelper.Encode(mbyte, 0, tmp, 0, tmp.Length, ASCIIEncoding.ASCII.GetBytes(""ABCDEFG2""));
            stream.Write(tmp, 0, tmp.Length);
            mstream.Close();
            stream.Close();
        }"));


            classType.Members.Add(new CodeSnippetTypeMember(
                                      @"public static void Deserialize(string filename, bool isAssetBundle = false) {
            TextAsset textAsset = null;
            if(isAssetBundle && AssetBundleMgr.ContainsFile(filename, ""bytes"")) {
                textAsset = AssetBundleMgr.Load(filename, "".bytes"") as TextAsset;
            }
            else {
                textAsset = Resources.Load(filename) as TextAsset;
            }
            BinaryFormatter formatter = new BinaryFormatter();
            MemoryStream mstream = new MemoryStream();
            byte[] tmp = new byte[textAsset.bytes.Length];
            CsvHelper.Encode(textAsset.bytes, 0, tmp, 0, tmp.Length, ASCIIEncoding.ASCII.GetBytes(""ABCDEFG2""));
            mstream.Write(tmp, 0, tmp.Length);
            mstream.Position = 0;
            " +
                                      string.Format("Data = formatter.Deserialize(mstream) as List<{0}>;", JumpCsvEditorHelper.GetCsvDataStructName(sheet.CsvFileName))));

            classType.Members.Add(new CodeSnippetTypeMember(
                                      @"    mstream.Close();    
        }"));
        }


        foreach (var method in BuildAccessMethods(sheet))
        {
            classType.Members.Add(method);
        }

        // add check sum
        classType.Members.Add(new CodeSnippetTypeMember(string.Format("public static int mHashCode = {0};", sheet.CalculateHashCode())));

        // add read method
        classType.Members.Add(BuildReadMethod(sheet));

        //classType.Members.Add(CreateSerializeMethod(sheet));
        //classType.Members.Add(BuildDeserializeMethod(sheet));

        return(classType);
    }
    private static CodeTypeDeclaration BuildCsvDataClassDeclarationLocalization(CsvSpreadSheet sheet)
    {
        string className = JumpCsvEditorHelper.GetCsvDataClassName(sheet.CsvFileName);
        CodeTypeDeclaration classType = new CodeTypeDeclaration(className);

        classType.IsClass        = true;
        classType.TypeAttributes = TypeAttributes.Public;

        classType.Members.Add(new CodeSnippetTypeMember(
                                  string.Format("public static Dictionary<{0}, {1}> Data = new Dictionary<{0}, {1}>();", "int", JumpCsvEditorHelper.GetCsvDataStructName(sheet.CsvFileName))));

        classType.Members.Add(new CodeSnippetTypeMember(
                                  string.Format("public static {0} GetRecord(int id)", JumpCsvEditorHelper.GetCsvDataStructName(sheet.CsvFileName))));
        classType.Members.Add(new CodeSnippetTypeMember(
                                  @"{ 
    if(Data.ContainsKey(id)) {
            return Data[id];
        }
        else {
            throw new Exception(""Can not find record by id "" + id);
        }
    }"));

        classType.Members.Add(new CodeSnippetTypeMember(
                                  @"public static void Serialize(string filename) {
        BinaryFormatter formatter = new BinaryFormatter();
        Stream stream = new FileStream(filename, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None);
        formatter.Serialize(stream, Data);
        stream.Flush();
        stream.Close();
    }"));


        classType.Members.Add(new CodeSnippetTypeMember(
                                  @"public static void Deserialize(string filename, bool isAssetBundle = false) {
        TextAsset textAsset = null;
        if(isAssetBundle && AssetBundleMgr.ContainsFile(filename, ""bytes"")) {
            textAsset = AssetBundleMgr.Load(filename, ""bytes"") as TextAsset;
        }
        else {
            textAsset = Resources.Load(filename) as TextAsset;
        }
        RecordIdValue.Clear();
        IdRecordValue.Clear();
        Init();
        Init2();
        BinaryFormatter formatter = new BinaryFormatter();
        Stream stream = new MemoryStream(textAsset.bytes);
        " +
                                  string.Format("Data = formatter.Deserialize(stream) as Dictionary<int, {0}>;", JumpCsvEditorHelper.GetCsvDataStructName(sheet.CsvFileName))));

        classType.Members.Add(new CodeSnippetTypeMember(
                                  @"    stream.Close();
    }"));

        CodeMemberField dicData = new CodeMemberField("Dictionary<int, string>", "RecordIdValue");

        dicData.Attributes = MemberAttributes.Static | MemberAttributes.Public;
        String intiString = "new Dictionary<int, string>()";

        dicData.InitExpression = new CodeSnippetExpression(intiString);

        classType.Members.Add(dicData);



        // add init
        StringBuilder intiStringBuild = new StringBuilder(1024);

        foreach (var t in sheet.Records)
        {
            intiStringBuild.Append(string.Format("{2}             RecordIdValue.Add({0},{1});", t.KeyValue, "\"" + t.KeyName + "\"", Environment.NewLine));
            //intiStringBuild.Append(string.Format("{2}            {{{0,-3}, {1,-30}}},", t.KeyValue,  "\""+t.KeyName+"\"", Environment.NewLine));
        }


        classType.Members.Add(new CodeSnippetTypeMember(
                                  "public static void Init() {\n" + intiStringBuild.ToString() + "\n}"
                                  ));

        //intiStringBuild.Append("new Dictionary<int, string>() {");

        StringBuilder intiStringBuild2 = new StringBuilder(1024);

        foreach (var t in sheet.Records)
        {
            intiStringBuild2.Append(string.Format("{2}             IdRecordValue.Add({0},{1});", "\"" + t.KeyName + "\"", t.KeyValue, Environment.NewLine));
            //intiStringBuild.Append(string.Format("{2}            {{{0,-3}, {1,-30}}},", t.KeyValue,  "\""+t.KeyName+"\"", Environment.NewLine));
        }

        classType.Members.Add(new CodeSnippetTypeMember(
                                  "public static void Init2() {\n" + intiStringBuild2.ToString() + "\n}"
                                  ));


        dicData                = new CodeMemberField("Dictionary<string, int>", "IdRecordValue");
        dicData.Attributes     = MemberAttributes.Static | MemberAttributes.Public;
        intiString             = "new Dictionary<string, int>()";
        dicData.InitExpression = new CodeSnippetExpression(intiString);

        classType.Members.Add(dicData);

        foreach (var method in BuildAccessMethods(sheet))
        {
            classType.Members.Add(method);
        }

        // add check sum
        classType.Members.Add(new CodeSnippetTypeMember(string.Format("public static int mHashCode = {0};", sheet.CalculateHashCode())));

        // add read method
        classType.Members.Add(BuildReadMethodLocalization(sheet));

        //classType.Members.Add(CreateSerializeMethod(sheet));
        //classType.Members.Add(BuildDeserializeMethod(sheet));

        return(classType);
    }
    private static CodeMemberMethod[] BuildAccessMethods(CsvSpreadSheet sheet)
    {
        List <CodeMemberMethod> result = new List <CodeMemberMethod>();

        foreach (var header in sheet.Header)
        {
            CodeMemberMethod method = new CodeMemberMethod();
            method.Attributes = MemberAttributes.Public | MemberAttributes.Static;
            Type returnType = header.Type;
            // method name
            if (returnType.IsArray)
            {
                method.Name = header.Name + "Array";
            }
            else
            {
                method.Name = header.Name;
            }

            // return type
            method.ReturnType = new CodeTypeReference(returnType);

            // parameters and return statement
            if (sheet.Kind == CsvSpreadSheet.EKind.ListRecord)
            {
                method.Parameters.Add(new CodeParameterDeclarationExpression(typeof(int), "index"));
                method.Statements.Add(new CodeMethodReturnStatement(new CodeSnippetExpression(string.Format("Data[index].{0}", header.Name))));
            }
            else if (sheet.Kind == CsvSpreadSheet.EKind.DicRecord)
            {
                method.Parameters.Add(new CodeParameterDeclarationExpression(typeof(int), "recordId"));
                method.Statements.Add(new CodeMethodReturnStatement(new CodeSnippetExpression(string.Format("GetRecord(recordId).{0}", header.Name))));
            }

            result.Add(method);


            if (returnType.IsArray)
            {
                CodeMemberMethod itemMethod = new CodeMemberMethod();

                itemMethod.Attributes = MemberAttributes.Public | MemberAttributes.Static;
                itemMethod.ReturnType = new CodeTypeReference(returnType.GetElementType());
                itemMethod.Name       = header.Name + "FromArray";
                if (sheet.Kind == CsvSpreadSheet.EKind.ListRecord)
                {
                    itemMethod.Parameters.Add(new CodeParameterDeclarationExpression(typeof(int), "index"));
                    itemMethod.Parameters.Add(new CodeParameterDeclarationExpression(typeof(int), "arrayIndex"));
                    itemMethod.Statements.Add(new CodeMethodReturnStatement(new CodeSnippetExpression(string.Format("Data[index].{0}[arrayIndex]", header.Name))));
                }
                else if (sheet.Kind == CsvSpreadSheet.EKind.DicRecord)
                {
                    itemMethod.Parameters.Add(new CodeParameterDeclarationExpression(typeof(int), "recordId"));
                    itemMethod.Parameters.Add(new CodeParameterDeclarationExpression(typeof(int), "arrayIndex"));
                    itemMethod.Statements.Add(new CodeMethodReturnStatement(new CodeSnippetExpression(string.Format("GetRecord(recordId).{0}[arrayIndex]", header.Name))));
                }
                result.Add(itemMethod);
            }
        }
        return(result.ToArray());
    }