const int x_axis_output_pin_5 = 5;
const int x_axis_output_pin_6 = 6;
const int x_axis_output_pin_7 = 7;
const int x_axis_output_pin_8 = 8;
int x_axis_distance_sensor_value = 0;
long x_axis_wheel_hole_counting = 0;
int x_axis_enable_interrupt = 0;
const int x_axis_left_limit_pin_a6 = A6;
const int x_axis_right_limit_pin_a7 = A7;

const int y_axis_output_pin_9 = 9;
const int y_axis_output_pin_10 = 10;
long y_axis_wheel_hole_counting = 0;
int y_axis_enable_interrupt = 0;
const int y_axis_up_limit_pin_11 = 11;
const int y_axis_down_limit_pin_12 = 12;

void called_when_a_x_axis_hole_passed() {
    if (x_axis_enable_interrupt == 1) {
        x_axis_wheel_hole_counting += 1;
    }
}

void called_when_a_y_axis_hole_passed() {
    if (y_axis_enable_interrupt == 1) {
        y_axis_wheel_hole_counting += 1;
    }
}

int digitalPinToInterrupt(int a_pin) {
    if (a_pin == 2) {
        return 0;
    } else if (a_pin == 3) {
        return 1;
    }
}

void x_axis_go_right() {
    analogWrite(x_axis_output_pin_5, 0);
    analogWrite(x_axis_output_pin_6, 255);
}

void x_axis_go_left() {
    analogWrite(x_axis_output_pin_6, 0);
    analogWrite(x_axis_output_pin_5, 255);
}

void x_axis_stop() {
    analogWrite(x_axis_output_pin_6, 0);
    analogWrite(x_axis_output_pin_5, 0);
}

void y_axis_go_up() {
    analogWrite(y_axis_output_pin_9, 0);
    analogWrite(y_axis_output_pin_10, 255);
}

void y_axis_go_down() {
    analogWrite(y_axis_output_pin_10, 0);
    analogWrite(y_axis_output_pin_9, 255);
}

void y_axis_stop() {
    analogWrite(y_axis_output_pin_9, 0);
    analogWrite(y_axis_output_pin_10, 0);
}

void x_axis_go_to_original_point() {
    x_axis_stop();
    x_axis_go_left();

    while (1) {
        if (analogRead(x_axis_left_limit_pin_a6) >= 500) {
            x_axis_stop();
            delay(1000);
            break;
        }
    }
}

/* 
for x axis:
0.1cm == 20 holes
we have 10 cm, which means (10/0.1) * 20 == 2000
*/

int x_axis_is_beyound_range() {
    if (analogRead(x_axis_left_limit_pin_a6) >= 500) {
        return 1;
    } else if (analogRead(x_axis_right_limit_pin_a7) >= 500) {
        return 2;
    }
    return 0;
}

void x_axis_go_for_x_holes(int the_direction, int holes_number) {
    x_axis_stop();
    x_axis_wheel_hole_counting = 0;

    x_axis_enable_interrupt = 1;
    int beyound = 0;
    int should_out = 0;
    while (1) {
        beyound = x_axis_is_beyound_range();
        if (the_direction == 1) {
            if (beyound != 2) {
                x_axis_go_right();
            } else {
                should_out = 1;
            }
        } else if (the_direction == -1) {
            if (beyound != 1) {
                x_axis_go_left();
            } else {
                should_out = 1;
            }
        }
        if ((x_axis_wheel_hole_counting >= holes_number) || (should_out == 1)) {
            x_axis_stop();
            x_axis_enable_interrupt = 0;
            x_axis_wheel_hole_counting = 0;
            break;
        }
    }
}

void y_axis_go_to_original_point() {
    y_axis_stop();
    y_axis_go_up();

    while (1) {
        if (digitalRead(y_axis_up_limit_pin_11) == 1) {
            y_axis_stop();
            delay(1000);
            break;
        }
    }
}

int y_axis_is_beyound_range() {
    if (digitalRead(y_axis_up_limit_pin_11) == 1) {
        return 2;
    } else if (digitalRead(y_axis_down_limit_pin_12) == 1) {
        return 1;
    }
    return 0;
}

void y_axis_go_for_x_holes(int the_direction, int holes_number) {
    y_axis_stop();
    y_axis_wheel_hole_counting = 0;

    y_axis_enable_interrupt = 1;
    int beyound = 0;
    int should_out = 0;
    while (1) {
        beyound = y_axis_is_beyound_range();
        //Serial.print("\nsensor = " );                       
        //Serial.print(beyound);      
        if (the_direction == 1) {
            if (beyound != 2) {
                y_axis_go_up();
            } else {
                should_out = 1;
            }
        } else if (the_direction == -1) {
            if (beyound != 1) {
                y_axis_go_down();
            } else {
                should_out = 1;
            }
        }
        if ((y_axis_wheel_hole_counting >= holes_number) || (should_out == 1)) {
            y_axis_stop();
            y_axis_enable_interrupt = 0;
            y_axis_wheel_hole_counting = 0;
            break;
        }
    }
}

void go_to_original_point() {
    x_axis_go_to_original_point();
    y_axis_go_to_original_point();
}

void go_right_for_x_cm(float x_cm) {
    int holes_number = int((x_cm / 0.1) * 20);
    x_axis_go_for_x_holes(1, holes_number);
}

void go_left_for_x_cm(float x_cm) {
    int holes_number = int((x_cm / 0.1) * 20);
    x_axis_go_for_x_holes(-1, holes_number);
}

void go_up_for_x_cm(float x_cm) {
    int holes_number = int((x_cm / 0.1) * 100);
    y_axis_go_for_x_holes(1, holes_number);
}

void go_down_for_x_cm(float x_cm) {
    int holes_number = int((x_cm / 0.1) * 100);
    y_axis_go_for_x_holes(-1, holes_number);
}

void pen_up() {
    //digitalWrite(x_axis_output_pin_7, LOW);
    digitalWrite(x_axis_output_pin_7, LOW);
}

void pen_down() {
    //digitalWrite(x_axis_output_pin_7, LOW);
    digitalWrite(x_axis_output_pin_7, HIGH);
}

void draw_a_point() {
    x_axis_stop();
    delay(10);

    pen_down();
    delay(10);
    pen_up();

    delay(10);
}

//void draw_a_character_original(int char_index, char *point_data) {
//    float x_min_distance = 0.05;
//    float y_min_distance = 0.02;
//
//    int index = 0;
//    char a_char = '.';
//
//    while (1) {
//        a_char = point_data[index];
//        index += 1;
//        //Serial.print(a_char);                       
//        if (a_char == ' ') {
//            x_axis_go_to_original_point();
//
//            go_right_for_x_cm((x_min_distance * (16 + 4)) * char_index);
//
//            go_up_for_x_cm(y_min_distance);
//            go_down_for_x_cm(y_min_distance * 2);
//            continue;
//        }
//        if (a_char == 'e') {
//            //end
//            go_to_original_point();
//            break;
//        }
//        if (a_char == '1') {
//            draw_a_point();
//            go_left_for_x_cm(x_min_distance);
//            go_right_for_x_cm(x_min_distance * 2);
//        }
//        if (a_char == '0') {
//            go_right_for_x_cm(x_min_distance);
//        }
//    }
//}

void draw_a_character(int char_index, char *point_data) {
    float x_min_distance = 0.05;
    float y_min_distance = 0.025;

    int index = 0;
    char a_char = '.';

    while (1) {
        a_char = point_data[index];
        index += 1;
        //Serial.print(a_char);                       
        if (a_char == ' ') {
            x_axis_go_to_original_point();

            go_right_for_x_cm((x_min_distance * (16 + 4)) * char_index);

            go_down_for_x_cm(y_min_distance);
            continue;
        }
        if (a_char == 'e') {
            //end
            go_to_original_point();
            break;
        }
        if (a_char == '1') {
            draw_a_point();
            go_right_for_x_cm(x_min_distance);
        }
        if (a_char == '0') {
            go_right_for_x_cm(x_min_distance);
        }
    }
}

//char *the_point_data = "0000000000000000 0111111111111100 0100000000000100 0100000100000100 0100000100000100 0100000100000100 0101111111110100 0100000100000100 0100001010000100 0100001001000100 0100010000100100 0100100000010100 0101000000010100 0100000000000100 0111111111111100 0100000000000100e";
//char *the_point_data3 = "0000000000000000 0000000000000000 1111111111111111 0000000100000000 0000000100000000 0000000100000000 0000000100000000 0000000100000000 0000000100000000 0000000100000000 0000000100000000 1111111111111111 0000000000000000 0000000000000000 0000000000000000 0000000000000000e";
char *wo = "0000010001000000 0000111001010000 0111100001001000 0000100001001000 0000100001000000 1111111111111110 0000100001000000 0000100001000100 0000101001000100 0000110001001000 0001100000110000 0110100000100010 0000100001010010 0000100010001010 0010101100000110 0001000000000010e";
char *ai = "0000000000001000 0000000111111100 0111111000010000 0010001000010000 0001000100100000 0111111111111110 0100001000000010 1000001000000100 0111111111111000 0000010000000000 0000011111110000 0000101000010000 0001000100100000 0010000011000000 0100001100110000 0001110000001110e";
char *ni = "0000100010000000 0000100010000000 0000100010000000 0001000111111110 0001000100000010 0011001000000100 0011010000100000 0101000000100000 1001000100101000 0001000100100100 0001001000100100 0001001000100010 0001010000100010 0001000000100000 0001000010100000 0001000001000000e";

void setup() {
    // initialize serial communications at 9600 bps:
    Serial.begin(9600); 

    // pin initialization
    pinMode(x_axis_output_pin_5, OUTPUT);
    pinMode(x_axis_output_pin_6, OUTPUT);
    pinMode(x_axis_output_pin_7, OUTPUT);
    pinMode(x_axis_output_pin_8, OUTPUT);
    pinMode(x_axis_left_limit_pin_a6, INPUT);
    pinMode(x_axis_right_limit_pin_a7, INPUT);

    pinMode(y_axis_up_limit_pin_11, INPUT);
    pinMode(y_axis_down_limit_pin_12, INPUT);

    delay(5000);
    pen_up();

    attachInterrupt(digitalPinToInterrupt(2), called_when_a_x_axis_hole_passed, FALLING);
    attachInterrupt(digitalPinToInterrupt(3), called_when_a_y_axis_hole_passed, FALLING);

    go_to_original_point();
    delay(1000);

    //go_right_for_x_cm(1.0);
    //go_down_for_x_cm(1.0);

    int i = 0;

    //i = 0;
    //while (i < 2) {
    //    int ii = 0;
    //    while (ii < 16) {
    //        draw_a_point();
    //        go_right_for_x_cm(0.05);
    //        ii += 1;
    //    }
    //    go_right_for_x_cm(1);
    //    i += 1;
    //}

    //i = 0;
    //while (i < 3) {
    //    int ii = 0;
    //    while (ii < 16) {
    //        draw_a_point();
    //        go_down_for_x_cm(0.05);
    //        ii += 1;
    //    }
    //    go_down_for_x_cm(1);
    //    i += 1;
    //}

    //return;

    //draw_a_character(0, the_point_data3);
    draw_a_character(0, wo);
    draw_a_character(1, ai);
    draw_a_character(2, ni);
}

int beyound = 0;
void loop() {
    /*
    beyound = y_axis_is_beyound_range();
    Serial.print("\nsensor = " );                       
    Serial.print(beyound);      
    */

    /*
    Serial.print("\nsensor = " );                       
    Serial.print(analogRead(x_axis_right_limit_pin_a7));      
    */
}
