Package org.gbcpainter.game.model.grid

Source Code of org.gbcpainter.game.model.grid.JunctionImpl

package org.gbcpainter.game.model.grid;

import org.gbcpainter.env.GraphicsEnv;
import org.gbcpainter.loaders.textures.TextureNotFoundException;
import org.gbcpainter.game.view.AbstractResourceDrawable;
import org.gbcpainter.game.view.animations.JunctionColoringAnimation;
import org.gbcpainter.geom.PERPENDICULAR_DIRECTION;
import org.gbcpainter.loaders.textures.TextureLoader;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.awt.*;
import java.util.*;

/**
* Implementation of the {@link org.gbcpainter.game.model.grid.Junction} interface
*
* @author Lorenzo Pellegrini
*/
public class JunctionImpl extends AbstractResourceDrawable implements Junction {

  @NonNls
  private static final String RESOURCE_NAME_PREFIX = "Junction_";

  @NonNls
  private static final String RESOURCE_HALF_NAME_PREFIX = "Junction_half_";

  private static final double HALF_ANIMATION_THRESHOLD = 0.10;

  @NonNls
  private static final char RESOURCE_UNSELECTED_FLAG = 'X';

  @NonNls
  private static final char RESOURCE_COLORED = 'C';

  @NonNls
  private static final Map<PERPENDICULAR_DIRECTION, Map.Entry<Character, Integer>> NAME_DIRECTIONS_MAPPING;
  @NotNull
  private final Collection<JunctionColoringAnimation> coloringAnimations = new LinkedList<>();
  @NotNull
  private final String resourceNameNotColored;
  @NotNull
  private final String resourceNameColored;

  @NotNull
  private final Set<PERPENDICULAR_DIRECTION> allowedDirections;

  @NotNull
  private final Point position;

  private boolean previousColor = false;

  static {
    NAME_DIRECTIONS_MAPPING = new EnumMap<>( PERPENDICULAR_DIRECTION.class );

    NAME_DIRECTIONS_MAPPING.put( PERPENDICULAR_DIRECTION.UP, new AbstractMap.SimpleImmutableEntry<>( 'U', 0 ) );
    NAME_DIRECTIONS_MAPPING.put( PERPENDICULAR_DIRECTION.DOWN, new AbstractMap.SimpleImmutableEntry<>( 'D', 1 ) );
    NAME_DIRECTIONS_MAPPING.put( PERPENDICULAR_DIRECTION.LEFT, new AbstractMap.SimpleImmutableEntry<>( 'L', 2 ) );
    NAME_DIRECTIONS_MAPPING.put( PERPENDICULAR_DIRECTION.RIGHT, new AbstractMap.SimpleImmutableEntry<>( 'R', 3 ) );
  }

  private boolean colored = false;



  /**
   * Creates a non colored junction with the given position and the relative position of the connected pipes
   *
   * @param junctionPosition   The position of the junction
   * @param directions The directions of the connected pipes
   *
   * @throws Exception                                              If an exception during texture loading
   * @throws org.gbcpainter.loaders.textures.InvalidTextureException If the base textures haven't the same size of the base point
   */

  public JunctionImpl(@NotNull Point junctionPosition, @NotNull Set<PERPENDICULAR_DIRECTION>
      directions) throws Exception {
    super();
    this.position = new Point( junctionPosition );
    int directionsCount = 0;
    this.allowedDirections = EnumSet.copyOf( directions );

    if ( directions.contains( PERPENDICULAR_DIRECTION.UP ) ) {
      directionsCount++;
    }
    if ( directions.contains( PERPENDICULAR_DIRECTION.DOWN ) ) {
      directionsCount++;
    }
    if ( directions.contains( PERPENDICULAR_DIRECTION.LEFT ) ) {
      directionsCount++;
    }
    if ( directions.contains( PERPENDICULAR_DIRECTION.RIGHT ) ) {
      directionsCount++;

    }

    final Collection<String> halfJunctionsResources;

    if ( directionsCount < 2 ) {
      //A junction with only 1 direction is not allowed!
      throw new IllegalArgumentException( "Junction has only " + directionsCount +
                                          "directions");
    } else if ( directionsCount == 2 ) {
      //2 Directions: junction can be colored from any of these directions
      halfJunctionsResources = new HashSet<>( 2 );
      final Deque<PERPENDICULAR_DIRECTION> allDirections = new LinkedList<>( directions );
      halfJunctionsResources.add( RESOURCE_HALF_NAME_PREFIX + getHalfResourceNameByDirections( directions, allDirections.removeFirst() ) );
      halfJunctionsResources.add( RESOURCE_HALF_NAME_PREFIX + getHalfResourceNameByDirections( directions, allDirections.removeFirst() ) );
    } else {
      /*
        3 or 4 Directions: if 3, junction can be colored from 3 of these but decolored from
        the perpendicular direction (this is the same texture as coloring from the
        lacking direction), so we need all half-coloring textures
       */
      halfJunctionsResources = new HashSet<>( 4 );
      halfJunctionsResources.add( RESOURCE_HALF_NAME_PREFIX + getHalfResourceNameByDirections( directions, PERPENDICULAR_DIRECTION.DOWN ) );
      halfJunctionsResources.add( RESOURCE_HALF_NAME_PREFIX + getHalfResourceNameByDirections( directions, PERPENDICULAR_DIRECTION.UP ) );
      halfJunctionsResources.add( RESOURCE_HALF_NAME_PREFIX + getHalfResourceNameByDirections( directions, PERPENDICULAR_DIRECTION.LEFT ) );
      halfJunctionsResources.add( RESOURCE_HALF_NAME_PREFIX + getHalfResourceNameByDirections( directions, PERPENDICULAR_DIRECTION.RIGHT ) );
    }

    final String resourceFromDirection = getResourceNameByDirections( directions );

    this.resourceNameNotColored = RESOURCE_NAME_PREFIX +
                                  RESOURCE_UNSELECTED_FLAG +
                                  resourceFromDirection;
    this.resourceNameColored = RESOURCE_NAME_PREFIX +
                               RESOURCE_COLORED +
                               resourceFromDirection;

    final TextureLoader loader = GraphicsEnv.getInstance().getTextureLoader();

    loader.loadTexture( this.resourceNameNotColored, true );

    loader.loadTexture( this.resourceNameColored, true );


    for (String halfJunctionResource : halfJunctionsResources) {
      loader.loadTexture( halfJunctionResource, true );
    }
  }

  @NonNls
  @NotNull
  private static String getResourceNameByDirections( @NotNull Set<PERPENDICULAR_DIRECTION> directions ) {
    @NonNls
    char[] result = { RESOURCE_UNSELECTED_FLAG, RESOURCE_UNSELECTED_FLAG, RESOURCE_UNSELECTED_FLAG, RESOURCE_UNSELECTED_FLAG };

    for (PERPENDICULAR_DIRECTION actualDirection : directions) {
      result[NAME_DIRECTIONS_MAPPING.get( actualDirection ).getValue()] = NAME_DIRECTIONS_MAPPING.get( actualDirection ).getKey();
    }

    return new String( result );
  }

  @NonNls
  @NotNull
  private static String getHalfResourceNameByDirections( @NotNull Set<PERPENDICULAR_DIRECTION> directions, @NotNull PERPENDICULAR_DIRECTION coloringDirection ) {
    @NonNls
    char[] result = { RESOURCE_UNSELECTED_FLAG, RESOURCE_UNSELECTED_FLAG, RESOURCE_UNSELECTED_FLAG, RESOURCE_UNSELECTED_FLAG };

    for (PERPENDICULAR_DIRECTION actualDirection : directions) {
      result[NAME_DIRECTIONS_MAPPING.get( actualDirection ).getValue()] = NAME_DIRECTIONS_MAPPING.get( actualDirection ).getKey();
    }

    final Character colorPart = NAME_DIRECTIONS_MAPPING.get( coloringDirection ).getKey();

    final StringBuilder builder = new StringBuilder();
    builder.append( colorPart );
    builder.append( result );
    return builder.toString();
  }

  @NotNull
  @Override
  public Set<PERPENDICULAR_DIRECTION> getAvailableDirections() {
    return EnumSet.copyOf( this.allowedDirections );
  }

  /**
   * Returns true if the point and the junction position are the same
   *
   * @param position A point in the game grid
   *
   * @return true if the point is at the junction position
   */
  @Override
  public boolean contains( @NotNull final Point position ) {
    return this.getPosition().equals( position );
  }

  @Override
  public synchronized boolean isColored() {
    return this.colored;
  }

  @Override
  public void setColored( @NotNull final Point point, final boolean colored )
      throws IllegalArgumentException {
    if(this.contains( point )) {
      this.setColored( colored );
    } else {
      throw new IllegalArgumentException( "Point is the junction position: " + point
                                          + ", expected: " + this.getPosition() );
    }
  }

  /**
   * Checks if a point is colored
   *
   * @param where The point to check
   *
   * @return true is colored
   *
   * @throws IllegalArgumentException If the point is not inside the grid element
   */
  @Override
  public boolean isColoredAt( @NotNull final Point where ) throws IllegalArgumentException {
    if(this.contains( where )) {
      return isColored( );
    } else {
      throw new IllegalArgumentException( "Point is the junction position: " + where
                                          + ", expected: " + getPosition() );
    }
  }

  /**
   * Returns the junction position
   * <p/>
   * This should be a constant
   *
   * @return The junction position
   */
  @NotNull
  @Override
  public Point getPosition() {
    return new Point( this.position );
  }

  /**
   * Sets the color flag of the junction
   *
   * @param colored true if colored, false if not colored
   */
  @Override
  public synchronized void setColored( final boolean colored ) throws TextureNotFoundException {
    this.colored = colored;
    final TextureLoader loader = GraphicsEnv.getInstance().getTextureLoader();

    final String requestedTexture;

    if ( colored ) {
      requestedTexture = this.resourceNameColored;
    } else {
      requestedTexture = this.resourceNameNotColored;
    }

    Image texture = loader.getTexture( requestedTexture, true );

    if ( texture == null ) {
      try {
        texture = loader.loadTexture( requestedTexture, true );
      } catch ( Exception e ) {
        throw new TextureNotFoundException( "Can't find texture " + requestedTexture, e );
      }
    }

    setDrawTexture( texture );
  }

  @Override
  public synchronized void applyAnimations( @NotNull final Collection<JunctionColoringAnimation> animations ) {
    this.coloringAnimations.clear();
    this.coloringAnimations.addAll( animations );
  }

  @Override
  public synchronized void clearAnimations() {
    this.coloringAnimations.clear();
    previousColor = isColored();
  }

  @Override
  @NonNls
  public String toString() {
    return "JunctionImpl{" +
           "coloringAnimations=" + coloringAnimations +
           ", resourceNameNotColored='" + resourceNameNotColored + '\'' +
           ", resourceNameColored='" + resourceNameColored + '\'' +
           ", allowedDirections=" + allowedDirections +
           ", previousColor=" + previousColor +
           ", colored=" + colored +
           "} " + super.toString();
  }

  @Nullable
  @Override
  protected synchronized String getResourceName() {
    boolean animationsTerminated = true;

    if ( ! this.coloringAnimations.isEmpty() ) {
      JunctionColoringAnimation bestAnimation = coloringAnimations.iterator().next();
      double higherNonFullPercentage = bestAnimation.getPercentageDoneAnimation();
      for (JunctionColoringAnimation coloringAnimation : this.coloringAnimations) {
        final double animationPercentage = coloringAnimation.getPercentageDoneAnimation();
        if ( animationPercentage > higherNonFullPercentage && ( animationPercentage != 1.0 || higherNonFullPercentage == 0.0 ) ) {
          higherNonFullPercentage = animationPercentage;
          bestAnimation = coloringAnimation;
        }

        if ( ! coloringAnimation.isTerminated() ) {
          animationsTerminated = false;
        }
      }

      if ( animationsTerminated ) {
        this.coloringAnimations.clear();
      } else if ( higherNonFullPercentage >= HALF_ANIMATION_THRESHOLD && previousColor != bestAnimation.isColoring() ) {
        @NotNull
        @NonNls
        final String suffixString;
        final PERPENDICULAR_DIRECTION animationDirection = bestAnimation.getDirection();
        Set<PERPENDICULAR_DIRECTION> directions = getAvailableDirections();


        if ( bestAnimation.isColoring() ) {
          suffixString = getHalfResourceNameByDirections( directions, animationDirection.getOpposite() );
        } else {
          Deque<PERPENDICULAR_DIRECTION> junctionDirections = new LinkedList<>( directions );

          if ( junctionDirections.size() == 2 ) {

            junctionDirections.remove( animationDirection.getOpposite() );
            final PERPENDICULAR_DIRECTION other = junctionDirections.getFirst();
            suffixString = getHalfResourceNameByDirections( directions, other );
          } else {
            suffixString = getHalfResourceNameByDirections( directions, animationDirection.getOpposite() );
          }
        }

        return RESOURCE_HALF_NAME_PREFIX + suffixString;
      } else {
        return previousColor ? resourceNameColored : resourceNameNotColored;
      }


    }
    return ( isColored() ) ? resourceNameColored : resourceNameNotColored;
  }
}
TOP

Related Classes of org.gbcpainter.game.model.grid.JunctionImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.