using System;
using System.Collections.Generic;
using UnityEngine;

public class MoleculeFactory : MonoBehaviour{

    public TextAsset jsonFile;

    private AtomeFactory atomeFactory;
    private static MoleculeFactory instance;

    private Molecules moleculesInJson;

    private Dictionary<string, Molecule>  moleculesDictionary;

    public MoleculeFactory(TextAsset jsonFile){
        MoleculeFactory.instance = this;
        moleculesDictionary = new Dictionary<string, Molecule>();
        moleculesInJson = JsonUtility.FromJson<Molecules>(jsonFile.text);
        foreach (var molecule in moleculesInJson.molecules){
            moleculesDictionary.Add(molecule.formula, molecule);
        }
    }

    public static MoleculeFactory getInstrance(){
        if(MoleculeFactory.instance == null){
            Debug.LogError("no Json file");
        }
        return MoleculeFactory.instance;
    }

        public static MoleculeFactory getInstrance(TextAsset jsonFile){
        if(MoleculeFactory.instance == null){
            MoleculeFactory.instance = new MoleculeFactory(jsonFile);
        }
        return MoleculeFactory.instance;
    }

    public Boolean hasMolecule(String formula)
    {
        return moleculesDictionary.ContainsKey(formula);
    }

    public GameObject createMolecule (string formula){
        if(!moleculesDictionary.ContainsKey(formula)){
            Debug.LogError("molecules does not existe in json");
        }
        Molecule molecule = moleculesDictionary[formula];
        GameObject sortie = new GameObject(molecule.name);
        foreach (Atom atom in molecule.atoms) {
            var template = GameObject.Find("SPHERE");
            var sphere = Instantiate(template, new Vector3(atom.geometry[0], atom.geometry[1], atom.geometry[2]), Quaternion.identity);
            //GameObject sphere = GameObject.CreatePrimitive(PrimitiveType.Sphere);
            sphere.transform.parent = sortie.transform;
            sphere.name = atom.element;
            sphere.transform.localPosition = new Vector3(atom.geometry[0], atom.geometry[1], atom.geometry[2]);
            AtomeInformation att = atomeFactory.createAtome(atom.element);
            Color myColor = new Color(0, 0, 1, 1);
            ColorUtility.TryParseHtmlString(att.representation.color, out myColor);
            sphere.GetComponent<Renderer>().material.color = myColor;
        }
        foreach (Bond bond in molecule.bonds){
            float atom1x = molecule.atoms[bond.atoms[0]].geometry[0];
            float atom2x = molecule.atoms[bond.atoms[1]].geometry[0];
            float atom1y = molecule.atoms[bond.atoms[0]].geometry[1];
            float atom2y = molecule.atoms[bond.atoms[1]].geometry[1];
            float atom1z = molecule.atoms[bond.atoms[0]].geometry[2];
            float atom2z = molecule.atoms[bond.atoms[1]].geometry[2];
            Vector3 vecAtom1 = new Vector3(atom1x, atom1y, atom1z);
            Vector3 vecAtom2 = new Vector3(atom2x, atom2y, atom2z);
            GameObject GObond = CreateCylinderBetweenPoints(vecAtom1,vecAtom2, 0.3f);
            GObond.transform.parent = sortie.transform;
        }
        return sortie;
    }

    public Molecule GetMoleculeByFormula(String formula)
    {
        if (!hasMolecule(formula))
        {
            return null;
        }
        Molecule molecule = moleculesDictionary[formula];
        return molecule;
    }

    public Dictionary<String, AtomeInformation> GetAtomsInfoByFormula(String formula)
    {
        if (!hasMolecule(formula))
        {
            return null;
        }
        Dictionary<String, AtomeInformation> dictionary = new Dictionary<string, AtomeInformation>();
        Molecule molecule = moleculesDictionary[formula];
        foreach (var atom in molecule.atoms)
        {
            dictionary.Add(atom.element, atomeFactory.createAtome(atom.element));
        }

        return dictionary;
    }

    public void setAtomFactory(AtomeFactory atomeFactory){
        this.atomeFactory = atomeFactory;
    }

    public AtomeFactory GetAtomFactory()
    {
        return this.atomeFactory;
    }

    private GameObject CreateCylinderBetweenPoints(Vector3 start, Vector3 end, float width){
        var offset = end - start;
        var scale = new Vector3(width, offset.magnitude / 2.0f, width);
        var position = start + (offset / 2.0f);

        var cylinderPrefab = GameObject.CreatePrimitive(PrimitiveType.Cylinder);
        cylinderPrefab.transform.position = position;
        cylinderPrefab.transform.rotation = Quaternion.identity;
        cylinderPrefab.transform.up = offset;
        cylinderPrefab.transform.localScale = scale;
        return cylinderPrefab;
    }

}