package de.rwth_aachen.graphics;

import org.lwjgl.util.vector.Vector3f;

import java.io.IOException;
import java.io.File;
import java.io.BufferedReader;
import java.io.FileReader;
import java.util.Vector;

/**
 * A cubic hermite spline used for smooth point interpolation.
 */
class CatmullRom
{
    private Vector<Vector3f> points;

    public CatmullRom(String f)
    {
        try
        {
            this.load(f);
        }
        catch(Exception e)
        {
            e.printStackTrace();
            System.err.println("Exception when loading "+f+", see above.");
        }
    }

    /** Load a point file from disk. */
    public void load(String f) throws IOException, NumberFormatException
    {
        points = new Vector<Vector3f>();

        File file = new File(f);
        BufferedReader br = new BufferedReader(new FileReader(file));

        String line = br.readLine();
        int l = 1;
        while(line!=null)
        {
            // parse line
            String[] coords = line.split(",");
            if(coords.length!=3)
                throw new IOException("Invalid path file "+f+", expected point"
                        +"tuple in line "+line+"!");

            float x = Float.parseFloat(coords[0]);
            float y = Float.parseFloat(coords[1]);
            float z = Float.parseFloat(coords[2]);

            this.points.add(new Vector3f(x, y, z));

            line = br.readLine();
            l++;
        }
    }

    /** Returns the point associated with the function value t. */
    public Vector3f getPoint(float t)
    {
        // Compute the parameters
        int i = (int)(t);
        int s = points.size();

        float x = t-i;
        float ix = 1.0f-x;

        // fetch the points
        Vector3f p0 = new Vector3f(points.elementAt((i+s-1)%s));
        Vector3f p1 = new Vector3f(points.elementAt((i    )%s));
        Vector3f p2 = new Vector3f(points.elementAt((i+1  )%s));
        Vector3f p3 = new Vector3f(points.elementAt((i+2  )%s));

        // compute the coefficients
        float c0 = ((2-x)*x-1)*x/2;
        float c1 = (((3*x-5)*x)*x+2)/2;
        float c2 = ((4-3*x)*x+1)*x/2;
        float c3 = ((x-1)*x*x)/2;

        // scale the points
        p0.scale(c0);
        p1.scale(c1);
        p2.scale(c2);
        p3.scale(c3);

        // cyclic add
        Vector3f r01 = new Vector3f();
        Vector3f r23 = new Vector3f();
        Vector3f r0123 = new Vector3f();
        Vector3f.add(p0, p1, r01);
        Vector3f.add(p2, p3, r23);
        Vector3f.add(r01, r23, r0123);

        return r0123;
    }
}
