using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using OpenGLSupport;
using PG_Sim.Support;
using System.IO;

namespace PG_Sim
{
    class Import
    {
        /// <summary>
        /// Handle to file
        /// </summary>
        private File file;

        /// <summary>
        /// Variables to handle with obj
        /// </summary>
        private List<bodyObj> bodies = new List<bodyObj>();                 // high layer
        private List<vertices> points = new List<vertices>();               // lowest layer

        /// <summary>
        /// Load string from file
        /// </summary>
        /// <param name="name">file name</param>
        public Import(string fileName)
        {
            // get contens from file
            file = new File(fileName);
        }

        /// <summary>
        /// Call a right function, depending on file type
        /// </summary>
        public List<bodyObj> Parse()
        {
            if (file.Extension == "obj")
                return this.ParseOBJ();
            else
                return new List<bodyObj>();
        }
        /// <summary>
        /// Load coordinates from txt file
        /// </summary>
        public double[][] loadPoints()
        {
            // convert . to , (localizate problem)
            file.RawData = file.RawData.Replace('.', ',');

            // split to lines
            string[] rows = file.RawData.Split('\n');

            // built array for points coordinates
            double[][] coords = new double[rows.Length][];
            int i = 0;

            foreach (string row in rows)
            {
                // split to words
                string[] cells = row.Trim('\r').Split(';');
                // prevent empty lines
                if (cells[0] != "")
                {
                    coords[i] = new double[] { Convert.ToDouble(cells[0]), Convert.ToDouble(cells[1]), Convert.ToDouble(cells[2]) };
                    i++;
                }
            }
            return coords;
        }

        #region OBJ handling
        /// <summary>
        /// Parse .obj file to triangles
        /// </summary>
        private List<bodyObj> ParseOBJ()
        {
            this.loadMtl();

            // convert . to , (localizate problem)
            file.RawData = file.RawData.Replace('.', ',');

            // split to lines
            string[] rows = file.RawData.Split('\n');

            //count bodies and lines
            int numModels = -1;
            int v = 0; int vt = 0;

            // go throught each lines
            foreach (string row in rows)
            {
                // split to words
                string[] cells = row.Trim('\r').Split(' ');

                if (cells[0] == "usemtl") // start of new body
                {
                    numModels++;
                }
                else if (numModels >= 0) // prevent first lines before body def
                {
                    if (cells[0] == "f") // define faces (complete triangle)
                    {
                        int a = getNum(cells[1]);
                        int b = getNum(cells[2]);
                        int c = getNum(cells[3]);

                        // in some cases is quads posible
                        if (cells.Length == 5)
                        {
                            int d = getNum(cells[4]);

                            // make a new square
                            bodies[numModels].addSquare(new quadsVect(points[a - 1], points[b - 1], points[c - 1], points[d - 1]));
                        }
                        else
                        {
                            // make a triangle
                            bodies[numModels].addTriangle(new trianglVect(points[a - 1], points[b - 1], points[c - 1]));
                        }
                    }
                    else if (cells[0] == "vt") // texture coordinates
                    {
                        // add tex coords to right point
                        points[vt].addTexture(float.Parse(cells[1]), float.Parse(cells[2]));
                        vt++;
                    }
                    else if (cells[0] == "v") // vertex coordinates
                    {
                        // get coords
                        float x = float.Parse(cells[1]);
                        float y = float.Parse(cells[2]);
                        float z = float.Parse(cells[3]);

                        // create a new vertex
                        points.Add(new vertices(x, y, z));
                        v++;
                    }
                }
            }
            return bodies;
        }

        /// <summary>
        /// Helper function to parse string for ex. 60/60/60 into int 60
        /// </summary>
        /// <param name="param">param with slashes</param>
        /// <returns>integer between slashes</returns>
        private int getNum(string param)
        {
            // parse into separate strings
            string[] nums = param.Trim().Split('/');

            // check for the equality of each string
            //if (nums[0] != nums[1] || nums[1] != nums[2] || nums[2] != nums[0])
            //    throw new InvalidDataException("Obj file is corrupted (" + param + ")");
            int num = Convert.ToInt32(nums[0]);
            return num;
        }
        #endregion;

        #region handling MTL file (part of obj)
        private void loadMtl()
        {
            File materials = new File("object/" + file.getName() + ".mtl");

            // convert . to , (localizate problem)
            materials.RawData = materials.RawData.Replace('.', ',');

            // split to lines
            string[] rows = materials.RawData.Split('\n');

            // enumerator
            int i = -1;

            // go throught each lines
            foreach (string row in rows)
            {
                // split to words
                string[] cells = row.Trim('\r').Split(' ');

                if (cells[0] == "newmtl") // set up a new material
                {
                    bodies.Add(new bodyObj(cells[1].Trim('\r')));
                    i++;
                }
                else if (cells[0] == "Kd") // save a body color
                {
                    bodies[i].setColor(row.Trim('\r'));
                }
                else if (cells[0] == "map_Kd") // save texture name
                {
                    bodies[i].setTexture(cells[1]);
                }
            }
        }
        #endregion;
    }
}
