package org.gbcpainter.view.editor;
import org.gbcpainter.env.GameSettings;
import org.gbcpainter.game.model.grid.Face;
import org.gbcpainter.geom.Segment;
import org.gbcpainter.loaders.level.LevelNotFoundException;
import org.gbcpainter.loaders.level.ParsingFailException;
import org.gbcpainter.loaders.level.parsers.AssertValidGraphParser;
import org.gbcpainter.loaders.level.parsers.FileLevelParser;
import org.gbcpainter.view.ViewManager;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jgrapht.Graph;
import org.jgrapht.graph.SimpleGraph;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.AffineTransform;
import java.awt.geom.GeneralPath;
import java.awt.geom.Line2D;
import java.io.*;
import java.nio.ByteBuffer;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
import java.util.List;
/**
* @author Lorenzo Pellegrini
*
* @exclude
*/
public class DummyCanvas extends Canvas {
private static final List<String> COMMON_EXTENSIONS = Arrays.asList( ".txt", ".level" );
private final SimpleGraph<Point, Segment> levelMap;
private final Map<Integer, Set<Segment>> rawFacesMap;
private final Point playerPosition;
private final Map<String, java.util.List<Point>> monstersPositions;
private final Rectangle levelBounds;
private final Map<Set<Segment>, Integer> facesMap;
@Nullable
private Map<Face, Integer> faces = null;
public DummyCanvas(@NotNull final String fileName)
throws IOException, ParsingFailException {
final FileLevelParser parser = new AssertValidGraphParser();
File levelsPath = GameSettings.getRelativeDirectory( GameSettings
.getInstance().getValue(
GameSettings.STRING_SETTINGS_TYPE.LEVELS_PATH ));
File levelFile = new File( levelsPath, fileName );
if ( ! levelFile.canRead() ) {
for (String extension : COMMON_EXTENSIONS) {
levelFile = new File( levelsPath, fileName + extension );
if ( levelFile.canRead() ) {
break;
}
}
}
if ( ! levelFile.canRead() ) {
throw new LevelNotFoundException( "Couldn't find level: " + levelFile
.getAbsolutePath() );
}
Path path = Paths.get( levelFile.getAbsolutePath() );
ByteBuffer buffer = ByteBuffer.wrap( Files.readAllBytes( path ) );
parser.parseData( buffer );
this.levelMap = parser.getLevelMap();
this.rawFacesMap = parser.getFacesMap();
this.playerPosition = parser.getPlayerPosition();
this.monstersPositions = parser.getMonstersPosition();
this.levelBounds = makeBoundRectangle( this.levelMap );
this.facesMap = new HashMap<>( this.rawFacesMap.size() );
for (Map.Entry<Integer, Set<Segment>> faceEntry : this.rawFacesMap.entrySet()) {
final Set<Segment> perSegments = new HashSet<>( faceEntry.getValue()
.size() );
final Integer actualFace = faceEntry.getKey();
for (Segment perimeterSegment : faceEntry.getValue()) {
perSegments.add( perimeterSegment );
}
this.facesMap.put( perSegments, actualFace );
}
System.out.println( this.tryCreateFaces() );
this.addMouseListener( new MouseAdapter() {
@Override
public void mouseReleased( final MouseEvent e ) {
try {
ViewManager.getMainView().swap( new DummyCanvas( fileName ) );
} catch ( Exception e1 ) {
System.out.println("Fail");
//ViewManager.getMainView().swap( new Label("Fail") );
}
}
} );
}
@NotNull
private static Rectangle makeBoundRectangle( @NotNull
Graph<Point,
Segment> levelGraph ) {
int minY = Integer.MAX_VALUE;
int maxY = 0;
int minX = Integer.MAX_VALUE;
int maxX = 0;
for (Point vertexPosition : levelGraph.vertexSet()) {
minX = Math.min( vertexPosition.x, minX );
maxX = Math.max( vertexPosition.x, maxX );
minY = Math.min( vertexPosition.y, minY );
maxY = Math.max( vertexPosition.y, maxY );
}
return new Rectangle( minX, minY, maxX - minX, maxY - minY );
}
@Override
public void paint(final Graphics g){
super.paint( g );
try {
final Graphics2D g2d = (Graphics2D) g;
Dimension screenBounds = this.getSize();
AffineTransform positionTransform = g2d.getTransform();
final double xRelation = (double) screenBounds.width / (double)
(this.levelBounds.width + 2);
final double yRelation = (double) screenBounds.height / (double)
(this.levelBounds.height + 2);
positionTransform.scale( xRelation, yRelation );
g2d.scale( xRelation, yRelation );
g2d.translate( -(this.levelBounds.x) + 1, -(this.levelBounds.y) + 1 );
g2d.setTransform( new AffineTransform( ) );
if ( this.faces != null ) {
g2d.setTransform( positionTransform );
for (Face face : this.faces.keySet()) {
face.draw( g2d );
}
g2d.setTransform( new AffineTransform( ) );
}
g2d.setColor( Color.RED);
for (Segment pipe : this.levelMap.edgeSet()) {
positionTransform.createTransformedShape( new Line2D.Double( pipe.getXA(), pipe.getYA(), pipe.getXB(),
pipe.getYB()) );
g2d.draw( positionTransform.createTransformedShape( new Line2D.Double( pipe.getXA(),
pipe.getYA(),
pipe.getXB(),
pipe.getYB() ) ) );
}
g2d.setColor( Color.GREEN);
for (Point junction : levelMap.vertexSet()) {
Point screenPosition = new Point( );
positionTransform.transform( junction, screenPosition );
g2d.drawRect(screenPosition.x - 1, screenPosition.y - 1,2,2 );
}
g2d.setColor( Color.BLUE );
for (Map.Entry<String, List<Point>> monsterEntry : this.monstersPositions.entrySet()) {
for (Point monsterPosition : monsterEntry.getValue()) {
Point screenPosition = new Point( );
positionTransform.transform( monsterPosition, screenPosition );
g2d.drawLine( screenPosition.x - 4, screenPosition.y -
4, screenPosition.x + 4, screenPosition.y + 4);
g2d.drawLine( screenPosition.x - 4, screenPosition.y +
4, screenPosition.x + 4,
screenPosition.y - 4);
}
}
g2d.setColor( Color.ORANGE);
Point screenPosition = new Point( );
positionTransform.transform( this.playerPosition, screenPosition );
g2d.drawRect(screenPosition.x - 4,screenPosition.y - 4,8,8 );
} catch ( Exception e ) {
e.printStackTrace();
}
}
protected boolean tryCreateFaces() {
boolean error = false;
this.faces = new HashMap<>( this.facesMap.size() );
try {
for (Map.Entry<Set<Segment>, Integer> faceAndId : this.facesMap.entrySet()) {
/* Per ogni faccia ... */
Segment firstPipe = faceAndId.getKey().iterator().next();
Point lastJunction = levelMap.getEdgeSource( firstPipe );
Segment lastPipe = null;
GeneralPath faceShape = new GeneralPath();
faceShape.moveTo( lastJunction.x, lastJunction.y );
while ( ! firstPipe.equals( lastPipe ) ) {
/* Aggiunge la linea*/
Segment nextPipe = null;
final Collection<Segment> connectedSegments = new HashSet<>(
this.levelMap.edgesOf(lastJunction ) );
if ( lastPipe == null ) {
/* È il primo loop */
lastPipe = firstPipe;
}
/* Scarta il segmento già percorso */
connectedSegments.remove( lastPipe );
for (Segment perimeterSegment : faceAndId.getKey()) {
/* Tra tutti i segmenti del perimetro seleziona solo quello che confina con il vertice corrente */
if ( connectedSegments.contains( perimeterSegment ) ) {
nextPipe = perimeterSegment;
break;
}
}
if ( nextPipe == null ) {
error = true;
lastPipe = firstPipe;
System.out.println("Error on face " + faceAndId.getValue());
System.out.println( "Perimeter: " + faceAndId.getKey() );
} else {
lastPipe = nextPipe;
final Point edgeSource = this.levelMap.getEdgeSource( nextPipe );
lastJunction = edgeSource.equals( lastJunction ) ? this.levelMap.getEdgeTarget( nextPipe ) : edgeSource;
faceShape.lineTo( lastJunction.x, lastJunction.y );
}
}
faceShape.closePath();
this.faces.put( new NotTransformedFace( faceShape ), faceAndId.getValue() );
}
if(error) {
System.out.println( "faces = " + this.faces );
}
return !error;
} catch ( Exception e ) {
this.faces = null;
return false;
}
}
}