/*
   * (non-Javadoc)
   *
   * @see br.org.archimedes.factories.SelectionPointVectorFactory#drawVisualHelper(br.org.archimedes.model.writers.Writer,
   *      java.util.Set, br.org.archimedes.model.Point,
   *      br.org.archimedes.model.Vector)
   */
  @Override
  protected void drawVisualHelper(Set<Element> selection, Point reference, Vector vector) {

    OpenGLWrapper opengl = br.org.archimedes.Utils.getOpenGLWrapper();
    for (Element element : selection) {
      Element copied = element.clone();
      try {
        Point start = reference;
        Point end = start.addVector(vector);

        List<Point> points = new LinkedList<Point>();
        points.add(start);
        points.add(end);
        opengl.drawFromModel(points);

        copied.mirror(start, end);
        copied.draw(opengl);
      } catch (NullArgumentException e) {
        // Should not happen
        e.printStackTrace();
      } catch (Exception e) {
        // Might happen, just ignore
      }
    }
  }
  public SortedSet<ComparablePoint> getSortedPointSet(
      InfiniteLine line, Point referencePoint, Collection<Point> intersectionPoints) {

    SortedSet<ComparablePoint> sortedPointSet = new TreeSet<ComparablePoint>();

    Point otherPoint = line.getInitialPoint();
    if (referencePoint.equals(line.getInitialPoint())) {
      otherPoint = line.getEndingPoint();
    }

    Vector direction = new Vector(referencePoint, otherPoint);
    for (Point point : intersectionPoints) {
      Vector pointVector = new Vector(referencePoint, point);
      double key = direction.dotProduct(pointVector);
      ComparablePoint element;
      try {
        element = new ComparablePoint(point, new DoubleKey(key));
        sortedPointSet.add(element);
      } catch (NullArgumentException e) {
        // Should never reach
        e.printStackTrace();
      }
    }

    return sortedPointSet;
  }
  public Collection<Element> trim(Element element, Collection<Point> cutPoints, Point click)
      throws NullArgumentException {

    if (element == null || cutPoints == null) {
      throw new NullArgumentException();
    }

    InfiniteLine line = (InfiniteLine) element;
    Collection<Element> trimResult = new ArrayList<Element>();

    SortedSet<ComparablePoint> sortedPointSet =
        getSortedPointSet(line, line.getInitialPoint(), cutPoints);

    Vector direction = new Vector(line.getInitialPoint(), line.getEndingPoint());

    Vector clickVector = new Vector(line.getInitialPoint(), click);
    double key = direction.dotProduct(clickVector);
    ComparablePoint clickPoint = null;
    try {
      clickPoint = new ComparablePoint(click, new DoubleKey(key));
    } catch (NullArgumentException e) {
      // Should never reach
      e.printStackTrace();
    }

    SortedSet<ComparablePoint> headSet = sortedPointSet.headSet(clickPoint);
    SortedSet<ComparablePoint> tailSet = sortedPointSet.tailSet(clickPoint);

    try {

      if (tailSet.size() > 0 && tailSet.first().getPoint().equals(clickPoint.getPoint())) {

        Point initialPoint = tailSet.first().getPoint();

        if (line.getInitialPoint().compareTo(line.getEndingPoint()) < 0) {
          direction = new Vector(line.getInitialPoint(), line.getEndingPoint());
        } else {
          direction = new Vector(line.getEndingPoint(), line.getInitialPoint());
        }

        clickPoint.getPoint().setX(clickPoint.getPoint().getX() + direction.getX());
        clickPoint.getPoint().setY(clickPoint.getPoint().getY() + direction.getY());

        Element trimmedLine = generateSemiline(clickPoint, initialPoint);
        trimmedLine.setLayer(line.getLayer());
        trimResult.add(trimmedLine);

      } else if (headSet.size() == 0 && tailSet.size() > 0) {
        Point initialPoint = tailSet.first().getPoint();
        Element trimmedLine = generateSemiline(clickPoint, initialPoint);
        trimmedLine.setLayer(line.getLayer());
        trimResult.add(trimmedLine);

      } else if (tailSet.size() == 0 && headSet.size() > 0) {
        Point initialPoint = headSet.last().getPoint();
        Element trimmedLine = generateSemiline(clickPoint, initialPoint);
        trimmedLine.setLayer(line.getLayer());
        trimResult.add(trimmedLine);

      } else if (headSet.size() > 0 && tailSet.size() > 0) {

        Point initialPoint = headSet.last().getPoint();
        Element trimmedLine = generateSemiline(clickPoint, initialPoint);
        trimmedLine.setLayer(line.getLayer());
        trimResult.add(trimmedLine);

        initialPoint = tailSet.first().getPoint();
        trimmedLine = generateSemiline(clickPoint, initialPoint);
        trimmedLine.setLayer(line.getLayer());
        trimResult.add(trimmedLine);
      }
    } catch (Exception e) {
      // Should not catch any exception
      e.printStackTrace();
    }

    return trimResult;
  }