package com.fer.labust.lawnmower.services;

import java.util.ArrayList;
import java.util.List;


import com.fer.labust.lawnmower.model.Line;
import com.fer.labust.lawnmower.model.Poligon;
import com.fer.labust.lawnmower.model.Point;


public class PlannerService {
	public static final Double INFINITY = Double.MAX_VALUE;
    private Poligon _poligon;
    private int _razmak;
    //private List<double> _nagibiPravaca = new List<double>(); 

    private Poligon poligon;

    private int razmak;

    public PlannerService(Poligon p, int razmak)
    {
        this._poligon = p;
        this._razmak = razmak;
    }
     public PlannerService()
     {
         
     }

    public double OdrediDuzinuStaze(List<Point> tocke )
    {
        double duzina = 0;
        int brojTocaka = tocke.size()-1; //da ne trazi spajanje zadnje i nepostojece
        for (int i = 0; i < brojTocaka;i++ )
        {
            duzina = duzina + tocke.get(i).getDistanceTo(tocke.get(i + 1));
        }
        return duzina;
    }

    public List<Point> pronadiTockePresjeka(List<Point> vrhovi)
    {
        Poligon poligon = new Poligon(vrhovi);
        List<Point> tockePresjeka = new ArrayList<Point>();
        double korak = odrediKorak(poligon);
        korak = 0.5;//------------------------------------------------!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
        Point a = new Point( poligon.getNajzapadnijaTocka().getLatitude(), poligon.getNajzapadnijaTocka().getLongitude() + korak);
        Point b = new Point( a.getLatitude() + 1, a.getLongitude());
        while (a.getLongitude() < poligon.getNajistocnijaTocka().getLongitude())
        {
            Line pravac = new Line(a, b);
            
            for (Line pLine : poligon.getPravci())
            {
                Point tockaPresjeka = pravac.sectionPoint(pLine);
                if (tockaPresjeka.isBetween(pLine.getFirstPoint(), pLine.getSecondPoint()))
                {
                    tockePresjeka.add(tockaPresjeka);
                }
            }
            a.setLongitude( a.getLongitude() + korak );
            b.setLongitude(b.getLongitude() + korak);
        }
        return tockePresjeka;
    }

    private double odrediKorak(Poligon p)
    {
        double sLatitude = (p.getNajistocnijaTocka().getLatitude() + p.getNajzapadnijaTocka().getLatitude()) / 2;
        Point zapadna = new Point(sLatitude, p.getNajzapadnijaTocka().getLongitude());
        Point istocna = new Point(sLatitude, p.getNajistocnijaTocka().getLongitude());
        double ukupnaUdaljenost = zapadna.getDistanceTo(istocna);
        double brDjelova = ukupnaUdaljenost / this._razmak;
        double korak = (p.getNajistocnijaTocka().getLongitude() - p.getNajzapadnijaTocka().getLongitude()) / brDjelova;
        return korak;
    }

    public List<Point> rotirajTocke(List<Point> Tocke, double kutRotacije)
    {
        List<Point> rotiraniVrhovi = new ArrayList<Point>();
        for (Point point : Tocke) {
        	Point noviVrh = new Point();
            noviVrh.setLongitude(point.getLongitude()*Math.cos(kutRotacije) - point.getLatitude()*Math.sin(kutRotacije));
            noviVrh.setLatitude(point.getLongitude()*Math.sin(kutRotacije) + point.getLatitude()*Math.cos(kutRotacije));
            rotiraniVrhovi.add(noviVrh);
		}  
        return rotiraniVrhovi;
    }

    public List<Point> odrediOptimalneTockePresjeka()
    {
        double duljinaStaze = INFINITY;
        double optimalniKutRotacije = 0;
        List<Point> tockePresjeka = new ArrayList<Point>();
        double kutRotacije = 0;
        while (kutRotacije <= Math.PI)
        {
            if(tockePresjeka.size()>0) tockePresjeka.clear();
            List<Point> vrhoviPoligona = rotirajTocke(_poligon.getVrhovi(), kutRotacije);
            tockePresjeka = pronadiTockePresjeka(vrhoviPoligona);
            double trenutnaDuzina = OdrediDuzinuStaze(tockePresjeka);
            if (trenutnaDuzina < duljinaStaze)
            {
                duljinaStaze = trenutnaDuzina;
                optimalniKutRotacije = kutRotacije;
            }
            kutRotacije = kutRotacije + Math.PI/180; 
        }
        List<Point> optimalnoRotiraniPoligon = rotirajTocke(_poligon.getVrhovi(), optimalniKutRotacije);
        List<Point> optimalneTockePresjekaRotirane = new ArrayList<Point>();
        optimalneTockePresjekaRotirane = pronadiTockePresjeka(optimalnoRotiraniPoligon);
        List<Point> praveTockePresjeka = rotirajTocke(optimalneTockePresjekaRotirane, -optimalniKutRotacije);    
        return praveTockePresjeka;
    }
    
	public Poligon getPoligon() {
		return poligon;
	}
	public void setPoligon(Poligon poligon) {
		this.poligon = poligon;
	}
	public int getRazmak() {
		return razmak;
	}
	public void setRazmak(int razmak) {
		this.razmak = razmak;
	}
}
