/*
 
* Copyright (c) 2016 Metron, Inc.
 
* All rights reserved.
 
*
 
* Redistribution and use in source and binary forms, with or without
 
* modification, are permitted provided that the following conditions are met:
 
*
     
* Redistributions of source code must retain the above copyright
 
*
       
notice, this list of conditions and the following disclaimer.
 
*
     
* Redistributions in binary form must reproduce the above copyright
 
*
       
notice, this list of conditions and the following disclaimer in the
 
*
       
documentation and/or other materials provided with the distribution.
 
*
     
* Neither the name of Metron, Inc. nor the
 
*
       
names of its contributors may be used to endorse or promote products
 
*
       
derived from this software without specific prior written permission.
 
*
 
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 
* DISCLAIMED. IN NO EVENT SHALL METRON, INC. BE LIABLE FOR ANY
 
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
*/
package com.metsci.glimpse.charts.shoreline;

import java.util.ArrayList;
import java.util.List;

/**
 
* @author hogye
 
*/
public class LandSegmentFactory
{
    
private final LandBox box;

    
public LandSegmentFactory( LandBox box )
    
{
        
this.box = box;
    
}

    
/**
     
* The returned LandSegment may have land on the wrong side. It is up
     
* to the calling code to detect this and correct for it.
     
*/

    
public LandSegment newLandSegment( List<LandVertex> vertices )
    
{
        
LandVertex start = vertices.get( 0 );
        
LandVertex end = vertices.get( vertices.size( ) - 1 );

        
if ( start.equals( end ) ) return LandSegment.newFillableSegment( vertices );

        
Edge startEdge = Edge.NONE;
        
if ( start.lat >= box.northLat )
            
startEdge = Edge.NORTH;
        
else if ( start.lat <= box.southLat )
            
startEdge = Edge.SOUTH;
        
else if ( start.lon >= box.eastLon )
            
startEdge = Edge.EAST;
        
else if ( start.lon <= box.westLon ) startEdge = Edge.WEST;

        
Edge endEdge = Edge.NONE;
        
if ( end.lat >= box.northLat )
            
endEdge = Edge.NORTH;
        
else if ( end.lat <= box.southLat )
            
endEdge = Edge.SOUTH;
        
else if ( end.lon >= box.eastLon )
            
endEdge = Edge.EAST;
        
else if ( end.lon <= box.westLon ) endEdge = Edge.WEST;

        
if ( startEdge == Edge.NONE || endEdge == Edge.NONE ) return LandSegment.newUnfillableSegment( vertices );

        
List<LandVertex> ghostVertices = new ArrayList<LandVertex>( );
        
if ( startEdge.isSame( endEdge ) )
        
{
            
// No ghost vertices needed
        
}
        
else if ( startEdge.isOpposite( endEdge ) )
        
{
            
switch ( startEdge )
            
{
                
case NORTH:
                
case SOUTH:
                    
ghostVertices.add( new LandVertex( end.lat, box.eastLon ) );
                    
ghostVertices.add( new LandVertex( start.lat, box.eastLon ) );
                    
break;

                
case EAST:
                
case WEST:
                    
ghostVertices.add( new LandVertex( box.northLat, end.lon ) );
                    
ghostVertices.add( new LandVertex( box.northLat, start.lon ) );
                    
break;
                
case NONE:
            
}
        
}
        
else if ( startEdge.isAdjacent( endEdge ) )
        
{
            
switch ( startEdge )
            
{
                
case NORTH:
                
case SOUTH:
                    
ghostVertices.add( new LandVertex( start.lat, end.lon ) );
                    
break;

                
case EAST:
                
case WEST:
                    
ghostVertices.add( new LandVertex( end.lat, start.lon ) );
                    
break;
                
case NONE:
            
}
        
}

        
return LandSegment.newFillableSegment( vertices, ghostVertices );
    
}

    
private static enum Edge
    
{
        
NONE, EAST, WEST, NORTH, SOUTH;

        
public boolean isSame( Edge edge )
        
{
            
return ( this != NONE && this == edge );
        
}

        
public boolean isOpposite( Edge edge )
        
{
            
switch ( this )
            
{
                
case EAST:
                    
return edge == WEST;
                
case WEST:
                    
return edge == EAST;
                
case NORTH:
                    
return edge == SOUTH;
                
case SOUTH:
                    
return edge == NORTH;
                
default:
                    
return false;
            
}
        
}

        
public boolean isAdjacent( Edge edge )
        
{
            
switch ( this )
            
{
                
case EAST:
                    
return edge == NORTH || edge == SOUTH;
                
case WEST:
                    
return edge == NORTH || edge == SOUTH;
                
case NORTH:
                    
return edge == EAST || edge == WEST;
                
case SOUTH:
                    
return edge == EAST || edge == WEST;
                
default:
                    
return false;
            
}
        
}
    
}

}