#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Polygon_2.h>
#include <string>
#include <vector>
#include <sstream>
#include <cstdlib>
#include <iostream>
#include <algorithm>

using namespace std;

// Define the CGAL kernel and associated types.
typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel;
typedef Kernel::Point_2 Point;              // For 2D points.
typedef CGAL::Polygon_2<Kernel> Polygon_2;    // For polygons.

// The Parachuter class contains the method overArea.
class Parachuter {
public:
    // overArea returns:
    //    0 if there is an input error (polygon is self-intersecting,
    //      has duplicate vertices, or a vertex lies on an edge),
    //    1 if the plane (planeX, planeY) is inside or exactly on the border
    //      of the polygon,
    //    2 if the plane is outside the polygon.
    //
    // Parameters:
    //    points: a vector of strings, each formatted as "(x,y)", representing
    //            the vertices of the polygon in order.
    //    planeX, planeY: the x and y coordinates of the plane.
    int overArea(const vector<string>& points, int planeX, int planeY) {
        // Check that we have at least 3 vertices to form a polygon.
        if (points.size() < 3)
            return 0;
        
        // Vector to store the parsed vertices as CGAL points.
        vector<Point> vertices;
        
        // Parse each coordinate string.
        // Expected format: "(x,y)" where x and y are integers.
        for (const string& s : points) {
            // Minimal valid string is "(0,0)" which is 5 characters.
            if (s.size() < 5)
                return 0;
            
            // Remove the surrounding parentheses.
            // For example, from "(10,20)" we get "10,20".
            string inside = s.substr(1, s.size() - 2);
            
            // Find the position of the comma.
            size_t commaPos = inside.find(',');
            if (commaPos == string::npos)
                return 0; // Invalid format if no comma is found.
            
            // Extract the substring for the x coordinate.
            string xStr = inside.substr(0, commaPos);
            // Extract the substring for the y coordinate.
            string yStr = inside.substr(commaPos + 1);
            
            int x_val, y_val;
            try {
                // Convert the substrings to integers.
                x_val = stoi(xStr);
                y_val = stoi(yStr);
            } catch (...) {
                // If conversion fails, the input is invalid.
                return 0;
            }
            
            // Create a CGAL point using the parsed coordinates.
            vertices.push_back(Point(x_val, y_val));
        }
        
        // Check for duplicate vertices.
        // A duplicate vertex means the polygon is invalid.
        for (size_t i = 0; i < vertices.size(); i++) {
            for (size_t j = i + 1; j < vertices.size(); j++) {
                if (vertices[i] == vertices[j])
                    return 0; // Duplicate vertex found.
            }
        }
        
        // Construct the polygon using the vertices in the order given.
        Polygon_2 poly;
        for (const Point& p : vertices) {
            poly.push_back(p);
        }
        
        // Check if the polygon is simple.
        // A non-simple polygon (i.e. one that self-intersects or has a vertex on an edge)
        // is considered invalid.
        if (!poly.is_simple())
            return 0;
        
        // Create a CGAL point for the plane's location.
        Point planePoint(planeX, planeY);
        
        // Determine the location of the point relative to the polygon.
        // CGAL's bounded_side() returns:
        //   ON_BOUNDED_SIDE  if the point is inside the polygon,
        //   ON_BOUNDARY      if the point is exactly on an edge,
        //   ON_UNBOUNDED_SIDE if the point is outside the polygon.
        CGAL::Bounded_side side = poly.bounded_side(planePoint);
        
        // If the point is inside or on the boundary, return 1.
        if (side == CGAL::ON_BOUNDED_SIDE || side == CGAL::ON_BOUNDARY)
            return 1;
        else
            // Otherwise, the point is outside the target area; return 2.
            return 2;
    }
};

////////////////////////////
/// Example Usage/Test:  ///
////////////////////////////

#define UNIT_TEST 1
#ifdef UNIT_TEST
#include <cassert>
int main(){
    Parachuter parachuter;
    
    // Test 1: A valid square polygon.
    vector<string> square = {"(0,0)", "(10,0)", "(10,10)", "(0,10)"};
    
    // Test point inside the square.
    int res = parachuter.overArea(square, 5, 5);
    cout << "Test 1 (inside): " << res << endl;
    assert(res == 1);
    
    // Test point outside the square.
    res = parachuter.overArea(square, 15, 5);
    cout << "Test 2 (outside): " << res << endl;
    assert(res == 2);
    
    // Test 3: Invalid polygon (duplicate vertex).
    vector<string> duplicate = {"(0,0)", "(10,0)", "(10,0)", "(0,10)"};
    res = parachuter.overArea(duplicate, 5, 5);
    cout << "Test 3 (duplicate vertex): " << res << endl;
    assert(res == 0);
    
    // Test 4: Self-intersecting polygon (bow-tie shape).
    vector<string> bowtie = {"(0,0)", "(10,10)", "(0,10)", "(10,0)"};
    res = parachuter.overArea(bowtie, 5, 5);
    cout << "Test 4 (self-intersecting): " << res << endl;
    assert(res == 0);
    
    vector<string> polygon1 = {"(0,0)", "(4,4)", "(0,4)", "(4,0)"};
    res = parachuter.overArea(polygon1, 5, 5);
    cout << "Test 5 (self-intersecting): " << res << endl;
    assert(res == 0);
    
    cout << "All tests passed." << endl;
    return 0;
}
#else
int main(){
    // For a submission, only the Parachuter class is needed.
    return 0;
}
#endif

