/*
 *   Copyright (C) 2014  Alfons Wirtz
 *   website www.freerouting.net
 *
 *   Copyright (C) 2017 Michael Hoffer <info@michaelhoffer.de>
 *   Website www.freerouting.mihosoft.eu
*
 *   This program is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation, either version 3 of the License, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License at <http://www.gnu.org/licenses/> 
 *   for more details.
 *
 * IntDirection.java
 *
 * Created on 3. Februar 2003, 08:17
 */

package eu.mihosoft.freerouting.geometry.planar;
import eu.mihosoft.freerouting.datastructures.Signum;

/**
 *
 * Implements an abstract class Direction as an equivalence class of IntVector's.
 *
 *
 * @author Alfons Wirtz
 */

public class IntDirection extends Direction implements java.io.Serializable
{
    
    
    public boolean is_orthogonal()
    {
        return ( x == 0 || y == 0 ) ;
    }
    
    public boolean is_diagonal()
    {
        return ( Math.abs(x) == Math.abs(y) ) ;
    }
    
    public Vector get_vector()
    {
        return new IntVector(x,y);
    }
    
    IntDirection(int p_x, int p_y)
    {
        x = p_x;
        y = p_y;
    }
    
    IntDirection(IntVector p_vector)
    {
        x = p_vector.x;
        y = p_vector.y;
    }
    
    
    
    int compareTo( IntDirection p_other )
    {
        if (y > 0)
        {
            if (p_other.y < 0)
            {
                return -1 ;
            }
            if (p_other.y == 0)
            {
                if (p_other.x > 0)
                {
                    return 1 ;
                }
                return -1 ;
            }
        }
        else if (y < 0)
        {
            if (p_other.y >= 0)
            {
                return 1 ;
            }
        }
        else // y == 0
        {
            if (x > 0)
            {
                if (p_other.y != 0 || p_other.x < 0)
                {
                    return -1 ;
                }
                return 0 ;
            }
            // x < 0
            if (p_other.y > 0 || p_other.y == 0 && p_other.x > 0)
            {
                return 1 ;
            }
            if (p_other.y < 0)
            {
                return -1 ;
            }
            return 0;
        }
        
        // now this direction and p_other are located in the same
        // open horizontal half plane
        
        double determinant = (double) p_other.x * y - (double) p_other.y * x;
        return Signum.as_int(determinant);
    }
    
    public Direction opposite()
    {
        return new IntDirection(-x, -y);
    }
    
    public Direction turn_45_degree(int p_factor)
    {
        int n = p_factor % 8 ;
        int new_x ;
        int new_y ;
        switch (n)
        {
            case 0: // 0 degree
                new_x = x;
                new_y = y;
                break;
            case 1: // 45 degree
                new_x = x - y ;
                new_y = x + y ;
                break;
            case 2: // 90 degree
                new_x = -y ;
                new_y = x ;
                break;
            case 3: // 135 degree
                new_x = -x - y ;
                new_y = x - y ;
                break;
            case 4: // 180 degree
                new_x = -x ;
                new_y = -y ;
                break;
            case 5: // 225 degree
                new_x = y - x ;
                new_y = -x - y ;
                break;
            case 6: // 270 degree
                new_x = y ;
                new_y = -x ;
                break;
            case 7: // 315 degree
                new_x = x + y ;
                new_y = y - x ;
                break;
            default:
                new_x = 0 ;
                new_y = 0 ;
        }
        return new IntDirection(new_x, new_y) ;
    }
    
    
    /**
     * Implements the Comparable interface.
     * Returns 1, if this direction has a strict bigger angle with
     * the positive x-axis than p_other_direction,
     * 0, if this direction is equal to p_other_direction,
     * and -1 otherwise.
     * Throws an exception, if p_other_direction is not a Direction.
     */
    public int compareTo(Direction p_other_direction)
    {
        return -p_other_direction.compareTo(this);
    }
    
    int compareTo(BigIntDirection p_other)
    {
        return -(p_other.compareTo(this));
    }
    
    final double determinant(IntDirection p_other)
    {
        return (double)x * p_other.y - (double)y * p_other.x;
    }    
        
    public final int x;
    public final int y;
}