/*
 * Copyright (c) 2016 Vivid Solutions.
 *
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License 2.0
 * and Eclipse Distribution License v. 1.0 which accompanies this distribution.
 * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v20.html
 * and the Eclipse Distribution License is available at
 *
 * http://www.eclipse.org/org/documents/edl-v10.php.
 */

package org.locationtech.jts.operation.valid;

import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.io.WKTReader;

import junit.framework.TestCase;


/**
 * Tests allowing IsValidOp to validate polygons with
 * Self-Touching Rings forming holes.
 * Mainly tests that configuring {@link IsValidOp} to allow validating
 * the STR validates polygons with this condition, and does not validate
 * polygons with other kinds of self-intersection (such as ones with Disconnected Interiors).
 * Includes some basic tests to confirm that other invalid cases remain detected correctly,
 * but most of this testing is left to the existing XML validation tests.
 *
 * @author Martin Davis
 * @version 1.7
 */
public class ValidSelfTouchingRingFormingHoleTest
    extends TestCase
{
  private static WKTReader rdr = new WKTReader();

  public ValidSelfTouchingRingFormingHoleTest(String name) {
    super(name);
  }

  public static void main(String[] args) {
    junit.textui.TestRunner.run(ValidSelfTouchingRingFormingHoleTest.class);
  }

  /**
   * Tests a geometry with both a shell self-touch and a hole self-touch.
   * This is valid if STR is allowed, but invalid in OGC
   */
  public void testShellAndHoleSelfTouch()
  {
    String wkt = "POLYGON ((0 0, 0 340, 320 340, 320 0, 120 0, 180 100, 60 100, 120 0, 0 0),   (80 300, 80 180, 200 180, 200 240, 280 200, 280 280, 200 240, 200 300, 80 300))";
    checkIsValidSTR(wkt, true);
    checkIsValidDefault(wkt, false);
  }

  /**
   * Tests a geometry representing the same area as in {@link #testShellAndHoleSelfTouch}
   * but using a shell-hole touch and a hole-hole touch.
   * This is valid in OGC.
   */
  public void testShellHoleAndHoleHoleTouch()
  {
    String wkt = "POLYGON ((0 0, 0 340, 320 340, 320 0, 120 0, 0 0),   (120 0, 180 100, 60 100, 120 0),   (80 300, 80 180, 200 180, 200 240, 200 300, 80 300),  (200 240, 280 200, 280 280, 200 240))";
    checkIsValidSTR(wkt, true);
    checkIsValidDefault(wkt, true);
  }

  /**
   * Tests an overlapping hole condition, where one of the holes is created by a shell self-touch.
   * This is never valid.
   */
  public void testShellSelfTouchHoleOverlappingHole()
  {
    String wkt = "POLYGON ((0 0, 220 0, 220 200, 120 200, 140 100, 80 100, 120 200, 0 200, 0 0),   (200 80, 20 80, 120 200, 200 80))";
    checkIsValidSTR(wkt, false);
    checkIsValidDefault(wkt, false);
  }

  /**
   * Ensure that the Disconnected Interior condition is not validated
   */
  public void testDisconnectedInteriorShellSelfTouchAtNonVertex()
  {
    String wkt = "POLYGON ((40 180, 40 60, 240 60, 240 180, 140 60, 40 180))";
    checkIsValidSTR(wkt, false);
    checkIsValidDefault(wkt, false);
  }

  /**
   * Ensure that the Disconnected Interior condition is not validated
   */
  public void testDisconnectedInteriorShellSelfTouchAtVertex()
  {
    String wkt = "POLYGON ((20 20, 20 100, 140 100, 140 180, 260 180, 260 100, 140 100, 140 20, 20 20))";
    checkIsValidSTR(wkt, false);
    checkIsValidDefault(wkt, false);
  }

  public void testShellCross()
  {
    String wkt = "POLYGON ((20 20, 120 20, 120 220, 240 220, 240 120, 20 120, 20 20))";
    checkIsValidSTR(wkt, false);
    checkIsValidDefault(wkt, false);
  }

  public void testShellCrossAndSTR()
  {
    String wkt = "POLYGON ((20 20, 120 20, 120 220, 180 220, 140 160, 200 160, 180 220, 240 220, 240 120, 20 120,  20 20))";
    checkIsValidSTR(wkt, false);
    checkIsValidDefault(wkt, false);
  }

  private void checkIsValidDefault(String wkt, boolean expected)
  {
    Geometry geom = fromWKT(wkt);
    IsValidOp validator = new IsValidOp(geom);
    boolean isValid = validator.isValid();
    assertTrue(isValid == expected);
  }

  private void checkIsValidSTR(String wkt, boolean expected)
  {
    Geometry geom = fromWKT(wkt);
    IsValidOp validator = new IsValidOp(geom);
    validator.setSelfTouchingRingFormingHoleValid(true);
    boolean isValid = validator.isValid();
    assertTrue(isValid == expected);
  }

  Geometry fromWKT(String wkt)
  {
    Geometry geom = null;
    try {
      geom = rdr.read(wkt);
    }
    catch (Exception ex) {
      ex.printStackTrace();
    }
    return geom;
  }

}
