Package org.gbcpainter.game.model.grid

Source Code of org.gbcpainter.game.model.grid.PipeImpl$PipePart

package org.gbcpainter.game.model.grid;

import net.jcip.annotations.GuardedBy;

import org.gbcpainter.env.GraphicsEnv;
import org.gbcpainter.loaders.textures.TextureNotFoundException;
import org.gbcpainter.game.view.animations.PipeColoringAnimation;
import org.gbcpainter.geom.ImmutableSegment2D;
import org.gbcpainter.geom.PERPENDICULAR_DIRECTION;
import org.gbcpainter.geom.Segment;
import org.gbcpainter.loaders.textures.TextureLoader;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;

import java.awt.*;
import java.awt.geom.Line2D;
import java.util.*;

/**
* Implementation of the {@link org.gbcpainter.game.model.grid.Pipe} interface
* <p/>
* Colored parts are saved as a couple of integer (start - end) instead of the state of the single points in order to save memory space.
*
* @author Lorenzo Pellegrini
*/
public final class PipeImpl implements Pipe {

  @NonNls
  private static final String NON_COLORED_PART_HORIZONTAL = "Pipe_nocolor_horizontal";

  @NonNls
  private static final String NON_COLORED_PART_VERTICAL = "Pipe_nocolor_vertical";

  @NonNls
  private static final String COLORED_PART_HORIZONTAL = "Pipe_color_horizontal";

  @NonNls
  private static final String COLORED_PART_VERTICAL = "Pipe_color_vertical";

  @NonNls
  private static final String COLORED_SLICE_HORIZONTAL = "Colored_pipe_horizontal";

  @NonNls
  private static final String NON_COLORED_SLICE_HORIZONTAL = "Not_colored_pipe_horizontal";

  @NonNls
  private static final String COLORED_SLICE_VERTICAL = "Colored_pipe_vertical";

  @NonNls
  private static final String NON_COLORED_SLICE_VERTICAL = "Not_colored_pipe_vertical";

  @NotNull
  private final Segment segment;
  @NotNull
  @GuardedBy ( "this" )
  private final Collection<PipeColoringAnimation> coloringAnimations = new HashSet<>( 2 );
  @NotNull
  @GuardedBy ( "this" )
  private final NavigableSet<PipePart> colorParts = new TreeSet<>();
  @NotNull
  @GuardedBy ( "this" )
  private final NavigableMap<Integer, Boolean> changedParts = new TreeMap<>();

  private final boolean voidPipe;

  private final boolean vertical;

  /**
   * Creates a non colored pipe at the position defined by a segment
   *
   * @param segment The segment that defines the position of the pipe
   *
   * @throws IllegalArgumentException                               If the segment is not perpendicular to x/y axes
   * @throws Exception                                              If an error occurs while loading textures
   * @throws org.gbcpainter.loaders.textures.InvalidTextureException If the base textures haven't the same size of the base point
   */
  public PipeImpl( @NotNull Segment segment ) throws Exception {
    if ( ! segment.isPerpendicular() ) {
      throw new IllegalArgumentException( "Segment is not parallel to X|Y axes" );
    }

    if ( segment.getA().equals( segment.getB() ) ) {
      throw new IllegalArgumentException( "Segment is a point" );
    }

    if ( isVertical( segment ) ) {
      this.vertical = true;
      if(segment.getMinY() == (segment.getMaxY()-1)) {
        this.voidPipe = true;
        this.segment = new ImmutableSegment2D( segment.getXA(), segment.getYA(),
                                               segment.getXB(), segment.getYB());
      } else {
        this.voidPipe = false;
        this.segment = new ImmutableSegment2D( segment.getXA(), segment.getMinY() + 1,
                                               segment.getXA(), segment.getMaxY() - 1 );
      }

    } else {
      this.vertical = false;
      if(segment.getMinX() == (segment.getMaxX()-1)) {
        this.voidPipe = true;
        this.segment = new ImmutableSegment2D( segment.getXA(), segment.getYA(),
                                               segment.getXB(), segment.getYB());
      } else {
        this.voidPipe = false;
        this.segment = new ImmutableSegment2D( segment.getMinX() + 1, segment.getYA(),
                                               segment.getMaxX() - 1, segment.getYA() );
      }
    }



    final TextureLoader loader = GraphicsEnv.getInstance().getTextureLoader();
    //final int baseDimension = GraphicsEnv.getInstance().getBasePointDimension();

    if(!this.voidPipe) {
      if ( isVertical( segment ) ) {
        loader.loadTexture( NON_COLORED_PART_VERTICAL, true );
        /*if ( loader.getBaseDimension( NON_COLORED_PART_VERTICAL ).height !=
              baseDimension ) {
          throw new InvalidTextureException( "Pipe texture " + NON_COLORED_PART_VERTICAL + " has an invalid size!" );
        }*/

        loader.loadTexture( COLORED_PART_VERTICAL, true );
        /*if ( loader.getBaseDimension( COLORED_PART_VERTICAL ).height != baseDimension ) {
          throw new InvalidTextureException( "Pipe texture " + COLORED_PART_VERTICAL + " has an invalid size!" );
        }*/

        loader.loadTexture( COLORED_SLICE_VERTICAL, true );
        loader.loadTexture( NON_COLORED_SLICE_VERTICAL, true );
      } else {
        loader.loadTexture( NON_COLORED_PART_HORIZONTAL, true );
        /*if ( loader.getBaseDimension( NON_COLORED_PART_HORIZONTAL ).width !=
              baseDimension ) {
          throw new InvalidTextureException( "Pipe texture " + NON_COLORED_PART_HORIZONTAL + " has an invalid size!" );
        }*/

        loader.loadTexture( COLORED_PART_HORIZONTAL, true );
        /*if ( loader.getBaseDimension( COLORED_PART_HORIZONTAL ).width != baseDimension ) {
          throw new InvalidTextureException( "Pipe texture " + COLORED_PART_HORIZONTAL + " has an invalid size!" );
        }*/

        loader.loadTexture( COLORED_SLICE_HORIZONTAL, true );
        loader.loadTexture( NON_COLORED_SLICE_HORIZONTAL, true );
      }
    }


  }

  /**
   * Utility method that check if a segment if vertical
   *
   * @param toBeTested The segment to be checked
   *
   * @return true if the segment is vertical
   */
  private static boolean isVertical( @NotNull Segment toBeTested ) {
    return toBeTested.getXA() == toBeTested.getXB();

  }

  /**
   * Gets the position of the pipe
   *
   * @return The position of the pipe
   */
  @NotNull
  @Override
  public Segment getSegment() {
    return new ImmutableSegment2D( this.segment );
  }

  @Override
  public synchronized void setColored( @NotNull Point point, boolean colored ) throws IllegalArgumentException {
    if(this.isVoidPipe()) {
      return;
    }

    final PipePart part;
    if ( ! this.contains( point ) ) {
      throw new IllegalArgumentException( "Point is not inside the pipe segment" );
    }

    if ( this.isVertical() ) {
      part = new PipePart( point.y, point.y );
      if ( ! this.changedParts.containsKey( point.y )
           &&  colored != this.isColoredAt( point.y )) {
        this.changedParts.put( point.y, ! colored );
      }
    } else {
      part = new PipePart( point.x, point.x );
      if ( ! this.changedParts.containsKey( point.x )
          && colored != this.isColoredAt( point.x )) {
        this.changedParts.put( point.x, !colored );
      }
    }

    if ( colored ) {
      this.doAddAndMerge( part );
    } else {
      this.doErase( part );
    }
  }

  public synchronized boolean isColoredAt( @NotNull Point where ) {


    if ( this.isVertical() ) {
      if ( where.x != this.segment.getXA() ) {
        throw new IllegalArgumentException();
      }

      if(this.isVoidPipe()) {
        return true;
      } else {
        return this.isColoredAt( where.y );
      }
    } else {
      if ( where.y != this.segment.getYA() ) {
        throw new IllegalArgumentException( "Point not in the pipe: " + where + "vs" +
                                            this.getSegment());
      }

      if(this.isVoidPipe()) {
        return true;
      } else {
        return this.isColoredAt( where.x );
      }
    }
  }

  @Override
  public synchronized void applyAnimations( @NotNull final Collection<PipeColoringAnimation> animations ) {
    if(!this.isVoidPipe()) {
      this.coloringAnimations.clear();
      if ( animations.isEmpty() ) {
        this.changedParts.clear();
      } else {
        this.coloringAnimations.addAll( animations );
      }

    }
  }

  @Override
  public synchronized void clearAnimations() {
    this.changedParts.clear();
    this.coloringAnimations.clear();
  }

  @Override
  public synchronized void reset() {
    this.clearAnimations();
    this.colorParts.clear();
  }

  @Override
  public synchronized void draw( @NotNull final Graphics2D g2 ) throws Exception {
    if(this.isVoidPipe()) {
      return;
    }

    final Iterable<PipePart> parts = new TreeSet<>( this.colorParts );
    final TextureLoader loader = GraphicsEnv.getInstance().getTextureLoader();
    final Segment pipeSegment = this.getSegment();

    final Dimension textureDimension;

    int gamePosition;
    final int upperLimit;

    /*
      Stampa le texure su schermo.

      Game position mantiene la posizione matematica della tubatura (model), e andrà dall'ascissa dell'estremo
      più a sinistra se la tubatura è orizzontale oppure dall'ordinata dell'estremo superiore se verticale.
      Upperlimit è impostato al limite opposto.

      Viene prima dipinta la parte non colorata, poi la parte colorata.

      screenPosition mantiene la posizione che deve avere la texture su schermo.

      screenPosition viene aggiornato a ogni pezzo di texture come un cursore.

      Questa parte riguarda il disegno delle sole parti non modificate in questo step.
     */
    Rectangle screenRect;
    Point screenPosition;
    final Iterator<Map.Entry<Integer, Boolean>> changedIterator = this.changedParts.entrySet()
                                                                               .iterator();
    Map.Entry<Integer, Boolean> nextSkip = changedIterator.hasNext() ? changedIterator.next() : null;

    if ( this.isVertical() ) {
      textureDimension = loader.getDimension( NON_COLORED_PART_VERTICAL );
      gamePosition = pipeSegment.getMinY();
      upperLimit = pipeSegment.getMaxY();

      for (final PipePart part : parts) {

        for (; gamePosition <= upperLimit && gamePosition < part.getStart(); gamePosition++) {
          screenRect = GraphicsEnv.getInstance().gamePointAndTextureToScreen( new Point( pipeSegment.getXA(), gamePosition ), textureDimension );
          screenPosition = new Point( screenRect.x, screenRect.y );
          final String pickTexture;

          if ( nextSkip != null && nextSkip.getKey() == gamePosition ) {
            pickTexture = ( nextSkip.getValue() ) ? COLORED_PART_VERTICAL : NON_COLORED_PART_VERTICAL;
            nextSkip = changedIterator.hasNext() ? changedIterator.next() : null;
          } else {
            pickTexture = NON_COLORED_PART_VERTICAL;
          }

          this.doDraw( g2, pickTexture, screenPosition );
        }

        for (; gamePosition <= part.getEnd(); gamePosition++) {
          screenRect = GraphicsEnv.getInstance().gamePointAndTextureToScreen( new Point( pipeSegment.getXA(), gamePosition ), textureDimension );
          screenPosition = new Point( screenRect.x, screenRect.y );
          final String pickTexture;

          if ( nextSkip != null && nextSkip.getKey() == gamePosition ) {
            pickTexture = ( nextSkip.getValue() ) ? COLORED_PART_VERTICAL : NON_COLORED_PART_VERTICAL;
            nextSkip = changedIterator.hasNext() ? changedIterator.next() : null;
          } else {
            pickTexture = COLORED_PART_VERTICAL;
          }

          this.doDraw( g2, pickTexture, screenPosition );
        }

      }

      for (; gamePosition <= upperLimit; gamePosition++) {
        screenRect = GraphicsEnv.getInstance().gamePointAndTextureToScreen( new Point( pipeSegment.getXA(), gamePosition ), textureDimension );
        screenPosition = new Point( screenRect.x, screenRect.y );
        final String pickTexture;

        if ( nextSkip != null && nextSkip.getKey() == gamePosition ) {
          pickTexture = ( nextSkip.getValue() ) ? COLORED_PART_VERTICAL : NON_COLORED_PART_VERTICAL;
          nextSkip = changedIterator.hasNext() ? changedIterator.next() : null;
        } else {
          pickTexture = NON_COLORED_PART_VERTICAL;
        }

        this.doDraw( g2, pickTexture, screenPosition );
      }

    } else {
      textureDimension = loader.getDimension( NON_COLORED_PART_HORIZONTAL );

      gamePosition = pipeSegment.getMinX();
      upperLimit = pipeSegment.getMaxX();

      for (final PipePart part : parts) {

        for (; gamePosition <= upperLimit && gamePosition < part.getStart(); gamePosition++) {
          screenRect = GraphicsEnv.getInstance().gamePointAndTextureToScreen( new Point( gamePosition, pipeSegment.getYA() ), textureDimension );
          screenPosition = new Point( screenRect.x, screenRect.y );
          final String pickTexture;

          if ( nextSkip != null && nextSkip.getKey() == gamePosition ) {
            pickTexture = ( nextSkip.getValue() ) ? COLORED_PART_HORIZONTAL : NON_COLORED_PART_HORIZONTAL;
            nextSkip = changedIterator.hasNext() ? changedIterator.next() : null;
          } else {
            pickTexture = NON_COLORED_PART_HORIZONTAL;
          }
          this.doDraw( g2, pickTexture, screenPosition );

        }

        for (; gamePosition <= part.getEnd(); gamePosition++) {

          screenRect = GraphicsEnv.getInstance().gamePointAndTextureToScreen( new Point( gamePosition, pipeSegment.getYA() ), textureDimension );
          screenPosition = new Point( screenRect.x, screenRect.y );
          final String pickTexture;

          if ( nextSkip != null && nextSkip.getKey() == gamePosition ) {
            pickTexture = ( nextSkip.getValue() ) ? COLORED_PART_HORIZONTAL : NON_COLORED_PART_HORIZONTAL;
            nextSkip = changedIterator.hasNext() ? changedIterator.next() : null;
          } else {
            pickTexture = COLORED_PART_HORIZONTAL;
          }
          this.doDraw( g2, pickTexture, screenPosition );
        }
      }

      for (; gamePosition <= upperLimit; gamePosition++) {

        screenRect = GraphicsEnv.getInstance().gamePointAndTextureToScreen( new Point( gamePosition, pipeSegment.getYA() ), textureDimension );
        screenPosition = new Point( screenRect.x, screenRect.y );
        final String pickTexture;

        if ( nextSkip != null && nextSkip.getKey() == gamePosition ) {
          pickTexture = ( nextSkip.getValue() ) ? COLORED_PART_HORIZONTAL : NON_COLORED_PART_HORIZONTAL;
          nextSkip = changedIterator.hasNext() ? changedIterator.next() : null;
        } else {
          pickTexture = NON_COLORED_PART_HORIZONTAL;
        }
        this.doDraw( g2, pickTexture, screenPosition );
      }

    }
    assert ! changedIterator.hasNext();

    /*
      Draws the modified parts on screen

      Modified parts are drawn as slices from the lower coordinate (leftmost X coordinate
      is horizontal, upper Y coordinate if vertical) to the upper one of the animation part
     */
    if ( ! this.coloringAnimations.isEmpty() ) {
      boolean remainingAnimations = false;
      if ( this.isVertical() ) {
        for (PipeColoringAnimation animation : this.coloringAnimations) {
          final Line2D donePart = animation.getDonePart();
          if ( donePart == null ) {
            continue;
          }

          final boolean colored = animation.isColoring();
          @NonNls
          final String selectedTexture = colored ? COLORED_SLICE_VERTICAL : NON_COLORED_SLICE_VERTICAL;
          final Dimension sliceDimension = loader.getDimension( selectedTexture );
          final Rectangle screenRealPosition = GraphicsEnv.getInstance().gamePointAndTextureToScreen( donePart.getP1(), sliceDimension );
          final Rectangle screenRealPositionUpper = GraphicsEnv.getInstance().gamePointAndTextureToScreen( donePart.getP2(), sliceDimension );
          final int lowerY = Math.min( screenRealPosition.y, screenRealPositionUpper.y );
          final int upperY = Math.max( screenRealPosition.y, screenRealPositionUpper.y );

          Point cursor = new Point( screenRealPosition.x, lowerY );
          for (; cursor.y < upperY; cursor.y++) {
            this.doDraw( g2, selectedTexture, cursor );
          }

          if ( ! animation.isTerminated() ) {
            remainingAnimations = true;
          }
        }
      } else {

        for (PipeColoringAnimation animation : this.coloringAnimations) {
          final Line2D donePart = animation.getDonePart();
          if ( donePart == null ) {
            continue;
          }

          final boolean colored = animation.isColoring();
          @NonNls
          final String selectedTexture = colored ? COLORED_SLICE_HORIZONTAL : NON_COLORED_SLICE_HORIZONTAL;
          final Dimension sliceDimension = loader.getDimension( selectedTexture );
          final Rectangle screenRealPosition = GraphicsEnv.getInstance().gamePointAndTextureToScreen( donePart.getP1(), sliceDimension );
          final Rectangle screenRealPositionUpper = GraphicsEnv.getInstance().gamePointAndTextureToScreen( donePart.getP2(), sliceDimension );
          final int lowerX = Math.min( screenRealPosition.x, screenRealPositionUpper.x );
          final int upperX = Math.max( screenRealPosition.x, screenRealPositionUpper.x );

          Point cursor = new Point( lowerX, screenRealPosition.y );
          for (; cursor.x < upperX; cursor.x++) {
            this.doDraw( g2, selectedTexture, cursor );
          }

          if ( ! animation.isTerminated() ) {
            remainingAnimations = true;
          }
        }
      }

      if ( ! remainingAnimations ) {
        this.clearAnimations();
      }
    }
  }

  /**
   * Utility method that adds a part of the pipe to the colored pipe parts data structure
   *
   * @param pivot The part to add
   */
  @GuardedBy ( "this" )
  private void doAddAndMerge( @NotNull PipePart pivot ) {
    final PipePart lower = this.colorParts.floor( pivot );

    if ( lower == null || ( lower.getEnd() + 1 ) < pivot.getStart() ) {
      this.colorParts.add( pivot );
    } else {
      if ( lower.getEnd() >= pivot.getEnd() ) {
        /* L'elemento esistente contiene il pivot */
        return;
      } else {
        lower.setEnd( pivot.getEnd() );
      }

      pivot = lower;
    }

    final NavigableSet<PipePart> upperPart = this.colorParts.tailSet( pivot, false );
    final Iterator<PipePart> goingUp = upperPart.iterator();
    while ( goingUp.hasNext() ) {
      final PipePart upper = goingUp.next();

      if ( upper.getEnd() <= pivot.getEnd() ) {
        goingUp.remove();
      } else if ( upper.getStart() <= ( pivot.getEnd() + 1 ) ) {
        pivot.setEnd( upper.getEnd() );
        goingUp.remove();
        break;
      } else {
        break;
      }
    }

  }

  /**
   * Utility method that erases a part of the pipe from the colored pipe parts data structure
   *
   * @param pivot The part to erase
   */
  @GuardedBy ( "this" )
  private void doErase( @NotNull PipePart pivot ) {
    final PipePart lower = this.colorParts.floor( pivot );

    if ( lower != null ) {

      if ( lower.getEnd() >= pivot.getStart() ) {
        /* Se l'elemento sotto interseca il pivot... */
        if ( lower.getStart() == pivot.getStart() ) {
          /* Se iniziano allo stesso punto */
          if ( lower.getEnd() <= pivot.getEnd() ) {
            /* Se l'elemento sotto è completamente contenuto nel pivot */
            this.colorParts.remove( lower );
          } else {
            /* Se l'elemento sotto è più lungo del pivot */
            lower.setStart( pivot.getEnd() + 1 );
          }
        } else {
          /* Se l'elemento sotto ha l'inizio più in basso */
          if ( lower.getEnd() > pivot.getEnd() ) {
            /* Se l'elemento sotto viene tagliato in 2 parti */
            this.colorParts.add( new PipePart( pivot.getEnd(), lower.getEnd() ) );
          }

          lower.setEnd( pivot.getStart() - 1 );

        }
      }
    }

    final NavigableSet<PipePart> upperPart = this.colorParts.tailSet( pivot, false);
    final Iterator<PipePart> goingUp = upperPart.iterator();
    while ( goingUp.hasNext() ) {
      final PipePart upper = goingUp.next();

      if ( upper.getEnd() <= pivot.getEnd() ) {
        /* Se l'elemento sopra è completamente contenuto dal pivot */
        goingUp.remove();
      } else if ( upper.getStart() <= pivot.getEnd() ) {
        /* Se l'elemento sopra interseca il pivot */
        upper.setStart( pivot.getEnd() );
        break;
      } else {
        /* Se non si intersecano */
        break;
      }
    }

  }

  private void doDraw( final @NotNull Graphics2D g2, final @NotNull String resourceName, final @NotNull Point where ) throws Exception {
    boolean done = false;
    boolean tryAcceleration = true;
    final TextureLoader loader = GraphicsEnv.getInstance().getTextureLoader();

    do {
      final Image img = loader.loadTexture( resourceName, tryAcceleration );
      g2.drawImage( img, where.x, where.y, null );
      try {
        if ( ! loader.mustReload( resourceName, tryAcceleration ) ) {
          done = true;
        }
      } catch ( NoSuchElementException e ) {
        if ( ! tryAcceleration ) {
          throw new TextureNotFoundException( e );
        }
        tryAcceleration = false;
      }
    } while ( ! done );
  }

  @NotNull
  @Override
  public Set<PERPENDICULAR_DIRECTION> getAvailableDirections() {
    if ( isVertical() ) {
      return new HashSet<>( Arrays.asList( PERPENDICULAR_DIRECTION.DOWN, PERPENDICULAR_DIRECTION.UP ) );
    } else {
      return new HashSet<>( Arrays.asList( PERPENDICULAR_DIRECTION.RIGHT, PERPENDICULAR_DIRECTION.LEFT ) );
    }
  }

  @Override
  public boolean contains( @NotNull final Point position ) {
    if(isVoidPipe()) {
      return false;
    }

    if ( isVertical() ) {
      if ( position.x == segment.getXA() && position.y >= segment.getMinY() && position.y <= segment.getMaxY() ) {
        return true;
      }

    } else {
      if ( position.y == segment.getYA() && position.x >= segment.getMinX() && position.x <= segment.getMaxX() ) {
        return true;
      }
    }

    return false;
  }

  @Override
  public synchronized boolean isColored() {
    if(isVoidPipe()) {
      return true;
    }

    if ( this.colorParts.size() == 1 ) {
      final PipePart part = this.colorParts.first();

      if ( isVertical() ) {
        if ( part.getStart() == segment.getMinY() && part.getEnd() == segment.getMaxY() ) {
          return true;
        }
      } else if ( part.getStart() == segment.getMinX() && part.getEnd() == segment.getMaxX() ) {
        return true;
      }
    }

    return false;
  }

  @GuardedBy ( "this" )
  private boolean isColoredAt( int where ) {
    if ( isVertical() ) {
      if ( where < this.segment.getMinY() || where > this.segment.getMaxY() ) {
        throw new IllegalArgumentException();
      }
    } else {
      if ( where < this.segment.getMinX() || where > this.segment.getMaxX() ) {
        throw new IllegalArgumentException();
      }
    }

    final PipePart pivotPart = new PipePart( where, where );
    final PipePart lower = this.colorParts.floor( pivotPart );
    if ( lower != null && lower.getEnd() >= where ) {
      return true;
    }


    final PipePart upper = this.colorParts.ceiling( pivotPart );
    return upper != null && upper.getStart() <= where;

  }

  /**
   * Checks if this pipe is vertical
   *
   * @return true if vertical, false if horizontal
   */
  private boolean isVertical() {
    return this.vertical;
  }

  private static class PipePart implements Comparable<PipePart> {

    private int start;
    private int end;

    PipePart( int start, int end ) {
      this.start = Math.min( start, end );
      this.end = Math.max( start, end );
    }

    @SuppressWarnings("unused")
    PipePart( @NotNull PipePart copy ) {
      this.start = copy.getStart();
      this.end = copy.getEnd();
    }

    public boolean equals( Object o ) {
      if ( o == null || ! ( o instanceof PipePart ) ) {
        return false;
      }

      return o == this || ( ( (PipePart) o ).getStart() == getStart() && ( (PipePart) o ).getEnd() == getEnd() );

    }

    @Override
    @NonNls
    public String toString() {
      return "PipePart{" +
             "start=" + start +
             ", end=" + end +
             '}';
    }

    int getStart() {
      return this.start;
    }

    void setStart( int start ) throws IllegalArgumentException {
      if ( start > getEnd() ) {
        throw new IllegalArgumentException();
      }
      this.start = start;
    }

    int getEnd() {
      return this.end;
    }

    void setEnd( int end ) throws IllegalArgumentException {
      if ( end < this.getStart() ) {
        throw new IllegalArgumentException();
      }
      this.end = end;
    }

    @Override
    public int compareTo( final @NotNull PipePart o ) {
      if ( this.getStart() > o.getStart() ) {
        return 1;
      }

      if ( this.getStart() < o.getStart() ) {
        return - 1;
      }

      return 0;
    }

  }

  @Override
  @NonNls
  public synchronized String toString() {
    return "PipeImpl{" +
           "segment=" + segment +
           ", coloringAnimations=" + coloringAnimations +
           ", colorParts=" + colorParts +
           ", changedParts=" + changedParts +
           ", voidPipe=" + voidPipe +
           '}';
  }

  public boolean isVoidPipe() {
    return this.voidPipe;
  }

}

TOP

Related Classes of org.gbcpainter.game.model.grid.PipeImpl$PipePart

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.