/* Write by
* Ekkalak Leelasornchai 5830622421
* Burin Naowarat 5831034621
* Progmeth project
*/
package model;
import javafx.application.Platform;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.input.KeyCode;
import javafx.scene.paint.Color;
import logic.GameLogic;
import logic.LineController;
import logic.Scorebar;
import screen.GameScreen;
import utility.InputUtility;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;
public class Line implements IDrawable{
private ArrayList<Point> points;
private Color color;
private ArrayList<Transporter> transporters;
private boolean isCreateTranFront;
Set<String> canGo;
public Line(Color color){
this.points = new ArrayList<>();
this.transporters = new ArrayList<>();
this.color = color;
isCreateTranFront = true;
canGo = new HashSet<String>();
}
public Line(Color color,ArrayList<Point> points){
this.points = new ArrayList<>(points);
this.transporters = new ArrayList<>();
this.color = color;
isCreateTranFront = true;
canGo = new HashSet<String>();
}
public Color getColor(){
return color;
}
public Point firstPoint(){
if(points.isEmpty()) return null;
return points.get(0);
}
public Point lastPoint(){
if(points.isEmpty()) return null;
return points.get(points.size()-1);
}
public void draw(GraphicsContext gc){
gc.setGlobalAlpha(1.0);
gc.setStroke(color);
gc.setLineWidth(10);
for(int i=0;i<points.size()-1;i++){
gc.strokeLine(points.get(i).getX(), points.get(i).getY(), points.get(i+1).getX(), points.get(i+1).getY());
}
gc.setFill(color);
if(firstPoint()!=null) gc.fillOval(firstPoint().getX()-23, firstPoint().getY()-23, 46, 46);
if(lastPoint()!=null) gc.fillOval(lastPoint().getX()-23, lastPoint().getY()-23, 46, 46);
}
public void drawPale(GraphicsContext gc){
gc.setStroke(color);
gc.setLineWidth(10);
gc.setGlobalAlpha(0.05);
for(int i=0;i<points.size()-1;i++){
gc.strokeLine(points.get(i).getX(), points.get(i).getY(), points.get(i+1).getX(), points.get(i+1).getY());
}
gc.setGlobalAlpha(1.0);
}
public void ap2(int x1,int y1,int x2,int y2){
Point p1 = new Point(x1, y1);
Point p2 = new Point(x2, y2);
this.getPoints().add(p1);
this.getPoints().add(p2);
}
public ArrayList<Point> getPoints(){
return points;
}
//public void addPoint(int x1,int y1,int x2,int y2,boolean append){
public void addPoint(Station s1,Station s2, boolean append){
int x1 = (int)s1.getCenterX(), y1 = (int)s1.getCenterY();
int x2 = (int)s2.getCenterX(), y2 = (int)s2.getCenterY();
ArrayList<Point> l1 = new ArrayList<>(); // for temp line
ArrayList<Point> l2 = new ArrayList<>(); // for temp line
// use direction for extends line
int directionx;
if(x2!=x1) directionx = (x2-x1)/Math.abs(x2-x1); // not divide by zero
else directionx = 0;
int directiony;
if(y2!=y1) directiony = (y2-y1)/Math.abs(y2-y1); // not divide by zero
else directiony = 0;
int inclineLength = Math.min(Math.abs(x2-x1), Math.abs(y2-y1));
int horizontalLength = Math.abs(Math.abs(x2-x1) - inclineLength);
int verticalLength = Math.abs(Math.abs(y2-y1) - inclineLength);
System.out.println(inclineLength);
System.out.println(horizontalLength);
System.out.println(verticalLength);
// horizontal first
if(horizontalLength>0){
l1.addAll(findHorizontal(x1, y1, directionx, horizontalLength));
}
if(inclineLength>0){
if(!l1.isEmpty()){
l1.addAll(findIncline(l1.get(l1.size()-1).getX() + directionx, l1.get(l1.size()-1).getY() + directiony, directionx, directiony, inclineLength-1));
}
else l1.addAll(findIncline(x1, y1, directionx, directiony, inclineLength));
}
if(verticalLength>0){
if(!l1.isEmpty()){
l1.addAll(findVertical(l1.get(l1.size()-1).getX(), l1.get(l1.size()-1).getY() + directiony, directiony, verticalLength-1));
}
else l1.addAll(findVertical(x1, y1, directiony, verticalLength));
}
// vertical first
if(verticalLength>0) l2.addAll(findVertical(x1, y1, directiony, verticalLength));
if(inclineLength>0){
if(!l2.isEmpty())
l2.addAll(findIncline(l2.get(l2.size()-1).getX() + directionx, l2.get(l2.size()-1).getY() + directiony, directionx, directiony, inclineLength-1));
else l2.addAll(findIncline(x1, y1, directionx, directiony, inclineLength));
}
if(horizontalLength>0){
if(!l2.isEmpty())
l2.addAll(findHorizontal(l2.get(l2.size()-1).getX() + directionx, l2.get(l2.size()-1).getY(), directionx, horizontalLength-1));
else l2.addAll(findHorizontal(x1, y1, directionx, horizontalLength));
}
// create temp line
Line tl1 = new Line(color,l1);
Line tl2 = new Line(color,l2);
// thread for catch chooseLineEvent when mouse is clicked
// and ESC to cancel creating line
Thread t = new Thread( () ->{ // thread for selecting which line to create
boolean isl1 = true;
while(true){
try {
Thread.sleep(75);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
break;
}
if(x2!=x1){
//find ccw or cw mouse pointer is to displacement line between station
if(ccw(new Point(x1,y1),new Point(x2,y2), new Point(InputUtility.getMouseX(),InputUtility.getMouseY()))){
if(directiony/directionx < 0 ){
LineHolder.getInstance().setTemp(tl2); isl1 = false;
}
else{
LineHolder.getInstance().setTemp(tl1); isl1 = true;
}
}
else{
if(directiony/directionx < 0 ){
LineHolder.getInstance().setTemp(tl1); isl1 = true;
}
else{
LineHolder.getInstance().setTemp(tl2); isl1 = false;
}
}
}
else{
LineHolder.getInstance().setTemp(tl1);
}
//System.out.println(InputUtility.isMouseLeftDown());
if(InputUtility.isMouseLeftDown()){ // catch clickig event for select line then extends/create
System.out.println("mouse down in Line");
boolean isCreate = points.isEmpty() ? true : false;
if(append){
if(isl1)points.addAll(l1);
else points.addAll(l2);
}
else{
if(isl1) addFront(l1);
else addFront(l2);
}
LineHolder.getInstance().removeTemp();
for(int i=0 ; i<LineController.getInstance().getColors().length ; i++ ){
if( color == LineController.getInstance().getColors()[i] ){
System.out.println("line founded in Line");
LineController.getInstance().getIsUsed()[i] = true;
}
}
s1.addLine(color);
s2.addLine(color);
addStationTypeToLine(s1,s2);
if(isCreate)GameLogic.addTransportToLine(this);
break;
}
else if(InputUtility.getKeyPressed(KeyCode.ESCAPE)){ // esc to cancel creating line
System.out.println("ESC down in Line");
LineHolder.getInstance().removeTemp();
for(int i=LineController.getInstance().getColors().length-1 ; i >= 0; i-- ){
if( color == LineController.getInstance().getColors()[i] ){
System.out.println("line founded in Line");
Line L = LineHolder.getInstance().getLine(color);
if(L != null && L.getPoints().size()==0 ){
LineHolder.getInstance().removeLine(color);
LineController.getInstance().getIsUsed()[i] = false;
}
break;
}
}
break;
}
}
});
ThreadHolder.instance.addThread(t);
t.start();
System.out.println("end thread");
System.out.println("points:" + points);
}
// public void addPoint(int x2,int y2){
// addPoint(points.get(points.size()-1).getX(),points.get(points.size()-1).getY(),x2,y2);
// }
public void clear() {
// TODO Auto-generated method stub
GraphicsContext gc = GameScreen.gc;
gc.setLineWidth(10);
gc.setStroke(Color.WHITESMOKE);
gc.setGlobalAlpha(1.0);
for(int i=0;i<points.size()-1;i++){
gc.strokeLine(points.get(i).getX(), points.get(i).getY(), points.get(i+1).getX(), points.get(i+1).getY());
}
}
private ArrayList<Point> findIncline(int x1,int y1,int directionx,int directiony,int inclineLength){
ArrayList<Point> line = new ArrayList<>();
int px = x1, py=y1, count=0;
while(count < inclineLength){
// incline line
line.add(new Point(px, py));
px += directionx;
py += directiony;
count ++;
}
line.add(new Point(px,py));
return line;
}
private ArrayList<Point> findHorizontal(int x1,int y1,int directionx,int horizontalLength){
ArrayList<Point> line = new ArrayList<>();
int px = x1, py = y1, count=0;
while(count < horizontalLength) {
// horizontal line
line.add(new Point(px,py));
px += directionx;
count++;
}
line.add(new Point(px,py));
return line;
}
private ArrayList<Point> findVertical(int x1,int y1,int directiony,int verticalLength){
ArrayList<Point> line = new ArrayList<>();
int px = x1, py=y1, count=0;
while(count < verticalLength){
// incline line
line.add(new Point(px, py));
py += directiony;
count++;
}
line.add(new Point(px,py));
return line;
}
private double cross(Point a, Point b) {
return a.getX() * b.getY() - a.getY() * b.getX();
}
private boolean ccw(Point p, Point q, Point r) {
if(p.getX()!=q.getX())
if((q.getY()-p.getY())/(q.getX()-p.getX()) < 0)
return cross(p.getVector(q), p.getVector(r)) < 0;
return cross(p.getVector(q), p.getVector(r)) < 0;
}
private void addFront(ArrayList<Point> t){
ArrayList<Point> temp = new ArrayList<>();
for(int i=t.size()-1 ; i>=0 ;i--){
temp.add(t.get(i));
}
int mov = temp.size();
temp.addAll(points);
points = new ArrayList<Point>(temp);
for(Transporter tr : transporters){
tr.positionIndex+=mov;
}
}
//***********************************************************************************************************************
// below these is transport ---------------------------------------------------------------------------------------------
public boolean addTransporter(){
if(points.isEmpty()){
System.out.println("line is empty cannot add transporter");
return false;
}
Transporter tran;
if(isCreateTranFront){
tran = new Transporter(firstPoint().getX(), firstPoint().getY(), color, 1);
tran.positionIndex = 0;
}
else{
tran = new Transporter(lastPoint().getX(), lastPoint().getY(), color, -1);
tran.positionIndex = points.size()-1;
}
isCreateTranFront = !isCreateTranFront;
transporters.add(tran);
Thread t = new Thread(()->{
int state = 0,count=0;
while(true){
try {
Thread.sleep(100);
Platform.runLater(()->{
tran.setX(points.get(tran.positionIndex).getX());
tran.setY(points.get(tran.positionIndex).getY());
});
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
break;
}
// moving
for(int i=0;i<Transporter.speed;i++){
Station st = StationHolder.getInstance().isStation(tran.x, tran.y);
int j = 0; // use j as state controller
if(st!=null && state <2 ){ // canGo station
// is can drop or transfer people?
count=0;
for(j=tran.passengers.size()-1 ; j>=0 && state == 0 ;j--){ // state 0 represent droping people
if(canGo(tran.passengers.get(j).getType())){
// drop people
if(tran.passengers.get(j).getType().compareTo(st.getType()) == 0){
tran.drop(j);
Scorebar.getInstance().setScore(Scorebar.getInstance().getScore()+1);
break;
}
}
else if(st.canGo(tran.passengers.get(j).getType())){
//transfer people
tran.transfer(j,st);
System.out.println("size:"+tran.passengers.size());
break;
}
}
if(j == -1) state = 1; // if doesn't drop any people then change state to loading people
// get people
if(!tran.isFull() && st.getNumberOfPassengers()>0 && state == 1){
tran.addPassenger(st.dequeuePassengers());
break;
}
else state = 2;
}
// moving
tran.positionIndex+=tran.direction;
if(tran.positionIndex<0){
tran.positionIndex = 0;
tran.direction = 1;
}
else if(tran.positionIndex>=points.size()){
tran.positionIndex = points.size()-1;
tran.direction = -1;
}
count++;
if(count==7) {
count=0;
state = 0;
}
}
}
}); // end thread
ThreadHolder.instance.addTransThread(LineController.getInstance().getColorIndex(color), t);
t.start();
return true;
}
public void drawTrans(GraphicsContext gc){
gc.setFill(color);
gc.setGlobalAlpha(1.0);
for(Transporter e : transporters){
e.draw(gc);
e.draw_passengers(gc);
}
}
public int length(){
return points.size();
}
private synchronized void addStationTypeToLine(Station s1,Station s2){
//TODO
canGo.add(s1.getType());
canGo.add(s2.getType());
}
public boolean canGo(String type){
return canGo.contains(type);
}
public int getNumberTransporter(){
return transporters.size();
}
}