/* Copyright 2021 Batuhan Başerdem
 * <baserdem.batuhan@gmail.com> @bbaserdem
 *
 * 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 2 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 for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
#include "bb-encoder.h"

// Need this to call velocikey activation
#ifdef VELOCIKEY_ENABLE
#   include "velocikey.h"
#endif // VELOCIKEY_ENABLE
// Need memcpy and memcmp from string.h along with transfer stuff
#ifdef OLED_ENABLE
#   include <string.h>
#endif // OLED_ENABLE

/* ROTARY ENCODER
 * This contains my general rotary encoder code
 * Encoders each have a list of different modes they can be in.
 * Each mode also have an on click action as well.
 * Modes can be cycled using either shift-click or ctrl-click
 * Modes can be reset using OS click
 * Some modes are only accessible through some keymap layers
 */

// Default state for the encoders
void reset_encoder_state(void) {
    userspace_config.e0base = 0;
    userspace_config.e0point = 0;
    userspace_config.e0rgb = 0;
    userspace_config.e1base = 1;
    userspace_config.e1point = 1;
    userspace_config.e1rgb = 1;
}

// Encoder scroll functionality
bool encoder_update_user(uint8_t index, bool clockwise) {
    uint8_t this_number;
    // Differentiate layer roles
    switch (get_highest_layer(layer_state)) {
#       ifdef RGB_MATRIX_ENABLE
        case _MEDI:
            // Get correct index
            if (index == 0) {
                this_number = userspace_config.e0rgb;
            } else if (index == 1) {
                this_number = userspace_config.e1rgb;
            } else {
                this_number = 128;
            }
            switch(this_number) {
                case 0: // Effect the RGB mode
                    if (clockwise) {
                        rgb_matrix_step_noeeprom();
                    } else {
                        rgb_matrix_step_reverse_noeeprom();
                    }
                    break;
                case 1: // Effect the RGB hue
                    if (clockwise) {
                        rgb_matrix_increase_hue_noeeprom();
                    } else {
                        rgb_matrix_decrease_hue_noeeprom();
                    }
                    break;
                case 2: // Effect the RGB saturation
                    if (clockwise) {
                        rgb_matrix_increase_sat_noeeprom();
                    } else {
                        rgb_matrix_decrease_sat_noeeprom();
                    }
                    break;
                case 3: // Effect the RGB brightness
                    if (clockwise) {
                        rgb_matrix_increase_val_noeeprom();
                    } else {
                        rgb_matrix_decrease_val_noeeprom();
                    }
                    break;
                case 4: // Effect the RGB effect speed
                    if (clockwise) {
                        rgb_matrix_increase_speed_noeeprom();
                    } else {
                        rgb_matrix_decrease_speed_noeeprom();
                    }
                    break;
            }
            break;
#       endif // RGB_MATRIX_ENABLE
#       ifdef MOUSEKEY_ENABLE
        case _MOUS:
            // Get correct index
            if (index == 0) {
                this_number = userspace_config.e0point;
            } else if (index == 1) {
                this_number = userspace_config.e1point;
            } else {
                this_number = 128;
            }
            switch(this_number) {
                case 0: // Move mouse on horizontal axis
                    if (clockwise) {
                        tap_code(KC_MS_R);
                    } else {
                        tap_code(KC_MS_L);
                    }
                    break;
                case 1: // Move mouse on vertical axis
                    if (clockwise) {
                        tap_code(KC_MS_D);
                    } else {
                        tap_code(KC_MS_U);
                    }
                    break;
                case 2: // Move mouse wheel on vertical axis
                    if (clockwise) {
                        tap_code(KC_WH_D);
                    } else {
                        tap_code(KC_WH_U);
                    }
                    break;
                case 3: // Move mouse on horizontal axis
                    if (clockwise) {
                        tap_code(KC_WH_R);
                    } else {
                        tap_code(KC_WH_L);
                    }
                    break;
            }
            break;
#       endif // MOUSEKEY_ENABLE
        default:
            // Get correct index
            if (index == 0) {
                this_number = userspace_config.e0base;
            } else if (index == 1) {
                this_number = userspace_config.e1base;
            } else {
                this_number = 128;
            }
            switch(this_number) {
                case 0: // Volume
                    if (clockwise) {
                        tap_code16(KC_VOLU);
                    } else {
                        tap_code16(KC_VOLD);
                    }
                    break;
                case 1: // Song change
                    if (clockwise) {
                        tap_code16(KC_MNXT);
                    } else {
                        tap_code16(KC_MPRV);
                    }
                    break;
                case 2: // Move to audio sink
                    if (clockwise) {
                        tap_code16(KC_F13);
                    } else {
                        tap_code16(S(KC_F13));
                    }
                    break;
                case 3: // Volume of source
                    if (clockwise) {
                        tap_code16(S(KC_VOLU));
                    } else {
                        tap_code16(C(KC_VOLD));
                    }
                    break;
                case 4: // Move to audio source
                    if (clockwise) {
                        tap_code16(C(KC_F13));
                    } else {
                        tap_code16(C(S(KC_F13)));
                    }
                    break;
                case 5: // Left-right
                    if (clockwise) {
                        tap_code16(KC_RGHT);
                    } else {
                        tap_code16(KC_LEFT);
                    }
                    break;
                case 6: // Up-down
                    if (clockwise) {
                        tap_code16(KC_DOWN);
                    } else {
                        tap_code16(KC_UP);
                    }
                    break;
                case 7: // Page Up-down
                    if (clockwise) {
                        tap_code16(KC_PGDN);
                    } else {
                        tap_code16(KC_PGUP);
                    }
                    break;
                case 8: // Delete 
                    if (clockwise) {
                        tap_code16(KC_DEL);
                    } else {
                        tap_code16(KC_BSPC);
                    }
                    break;
            }
            break;
    }
    return false;
}

void encoder_click_action(uint8_t index) {
    uint8_t this_number;
    // Differentiate layer roles
    switch (get_highest_layer(layer_state)) {
#       ifdef RGB_MATRIX_ENABLE
        case _MEDI:
            // Get correct index
            if (index == 0) {
                this_number = userspace_config.e0rgb;
            } else if (index == 1) {
                this_number = userspace_config.e1rgb;
            } else {
                this_number = 128;
            }
            switch(this_number) {
                case 0: // Return to no animation
                    rgb_matrix_mode_noeeprom(RGB_MATRIX_SOLID_COLOR);
                    break;
                case 1:
                case 2:
                case 3: // Toggle
                    rgb_matrix_increase_val_noeeprom();
                    break;
                case 4: // Toggle velocikey
#                   ifdef VELOCIKEY_ENABLE
                    velocikey_toggle();
#                   endif // VELOCIKEY_ENABLE
                    break;
            }
            break;
#       endif // RGB_MATRIX_ENABLE
#       ifdef MOUSEKEY_ENABLE
        case _MOUS:
            // Get correct index
            if (index == 0) {
                this_number = userspace_config.e0point;
            } else if (index == 1) {
                this_number = userspace_config.e1point;
            } else {
                this_number = 128;
            }
            switch(this_number) {
                case 0: // Left click
                    tap_code16(KC_BTN1);
                    break;
                case 1: // Right click
                    tap_code16(KC_BTN2);
                    break;
                case 2:
                case 3: // Middle click
                    tap_code16(KC_BTN2);
                    break;
            }
            break;
#       endif // MOUSEKEY_ENABLE
        default:
            // Get correct index
            if (index == 0) {
                this_number = userspace_config.e0base;
            } else if (index == 1) {
                this_number = userspace_config.e1base;
            } else {
                this_number = 128;
            }
            switch(this_number) {
                case 0: // Toggle mute
                case 2:
                    tap_code16(KC_MUTE);
                    break;
                case 1: // Pause
                    tap_code16(KC_MPLY);
                    break;
                case 3: // Mute source
                case 4:
                    tap_code16(A(KC_MUTE));
                    break;
                case 5: // Insert
                    tap_code16(KC_INS);
                    break;
                case 6: // Capslock
                    tap_code16(KC_CAPS);
                    break;
                case 7: // Redo
                    tap_code16(BB_REDO);
                    break;
                case 8: // Undo
                    tap_code16(BB_UNDO);
                    break;
            }
            break;
    }
}

bool process_record_encoder(uint16_t keycode, keyrecord_t *record) {
    // Check if and which encoder
    int encoder_index = -1;
    
    // Get the pressed encoder
    switch (keycode) {
        case BB_ENC0:
            encoder_index = 0;
            break;
        case BB_ENC1:
            encoder_index = 1;
            break;
    }

    // Activate encoder function of button
    if ((encoder_index >= 0) & (!record->event.pressed)) {
        // If shifted, move mode one point forward
        if (get_mods() & MOD_MASK_SHIFT) {
            switch (get_highest_layer(layer_state)) {
#               ifdef RGB_MATRIX_ENABLE
                case _MEDI:
                    if (encoder_index == 0) {
                        userspace_config.e0rgb = (userspace_config.e0rgb + 1) % 5;
                    } else {
                        userspace_config.e1rgb = (userspace_config.e1rgb + 1) % 5;
                    }
                    break;
#               endif // RGB_MATRIX_ENABLE
#               ifdef MOUSEKEY_ENABLE
                case _MOUS:
                    if (encoder_index == 0) {
                        userspace_config.e0point = (userspace_config.e0point + 1) % 4;
                    } else {
                        userspace_config.e1point = (userspace_config.e1point + 1) % 4;
                    }
                    break;
#               endif // MOUSEKEY_ENABLE
                default:
                    if (encoder_index == 0) {
                        userspace_config.e0base = (userspace_config.e0base + 1) % 9;
                    } else {
                        userspace_config.e1base = (userspace_config.e1base + 1) % 9;
                    }
                    break;
            }
        // If ctrl is active, move mode one point backwards
        } else if (get_mods() & MOD_MASK_CTRL) {
            switch (get_highest_layer(layer_state)) {
#               ifdef RGB_MATRIX_ENABLE
                case _MEDI:
                    if (encoder_index == 0) {
                        userspace_config.e0rgb = (userspace_config.e0rgb + 5 - 1) % 5;
                    } else {
                        userspace_config.e1rgb = (userspace_config.e1rgb + 5 - 1) % 5;
                    }
                    break;
#               endif // RGB_MATRIX_ENABLE
#               ifdef MOUSEKEY_ENABLE
                case _MOUS:
                    if (encoder_index == 0) {
                        userspace_config.e0point = (userspace_config.e0point + 4 - 1) % 4;
                    } else {
                        userspace_config.e1point = (userspace_config.e1point + 4 - 1) % 4;
                    }
                    break;
#               endif // MOUSEKEY_ENABLE
                default:
                    if (encoder_index == 0) {
                        userspace_config.e0base = (userspace_config.e0base + 9 - 1) % 9;
                    } else {
                        userspace_config.e1base = (userspace_config.e1base + 9 - 1) % 9;
                    }
                    break;
            }
        // If meta is active, reset the encoder states
        } else if (get_mods() & MOD_MASK_GUI) {
            reset_encoder_state();
            eeconfig_update_user(userspace_config.raw);
        // If nothing else; just perform the click action
        } else {
            encoder_click_action(encoder_index);
        }
    }
    return true;
}

// For printing status to OLED
#ifdef OLED_ENABLE
void encoder_state_string(uint8_t index, uint8_t layer, char* buffer) {
    uint8_t this_number;
    // Get the layer straight from the main function
    switch (layer) {
        // If RGB control mode is enabled
#       ifdef RGB_MATRIX_ENABLE
        case _MEDI:
            // Get correct index
            if (index == 0) {
                this_number = userspace_config.e0rgb;
            } else if (index == 1) {
                this_number = userspace_config.e1rgb;
            } else {
                this_number = 128;
            }
            switch (this_number) {
                case 0:
                    strcpy(buffer, "ani mode");
                    break;
                case 1:
                    strcpy(buffer, "hue     ");
                    break;
                case 2:
                    strcpy(buffer, "saturat.");
                    break;
                case 3:
                    strcpy(buffer, "bright. ");
                    break;
                case 4:
                    strcpy(buffer, "ani. spd");
                    break;
                default:
                    strcpy(buffer, " -N/A-  ");
                    break;
            }
            break;
#       endif // RGB_MATRIX_ENABLE
        // If pointer control is enabled
#       ifdef MOUSEKEY_ENABLE
        case _MOUS:
            // Get correct index
            if (index == 0) {
                this_number = userspace_config.e0point;
            } else if (index == 1) {
                this_number = userspace_config.e1point;
            } else {
                this_number = 128;
            }
            switch (this_number) {
                case 0:
                    strcpy(buffer, "Lateral ");
                    break;
                case 1:
                    strcpy(buffer, "Vertical");
                    break;
                case 2:
                    strcpy(buffer, "Scr. Ver");
                    break;
                case 3:
                    strcpy(buffer, "Scr. Lat");
                    break;
                default:
                    strcpy(buffer, " -N/A-  ");
                    break;
            }
            break;
#       endif // MOUSEKEY_ENABLE
        default:
            // Get correct index
            if (index == 0) {
                this_number = userspace_config.e0base;
            } else if (index == 1) {
                this_number = userspace_config.e1base;
            } else {
                this_number = 128;
            }
            switch (this_number) {
                case 0:
                    strcpy(buffer, "Volume  ");
                    break;
                case 1:
                    strcpy(buffer, "Song    ");
                    break;
                case 2:
                    strcpy(buffer, "Sink    ");
                    break;
                case 3:
                    strcpy(buffer, "Src. Vol");
                    break;
                case 4:
                    strcpy(buffer, "Source  ");
                    break;
                case 5:
                    strcpy(buffer, "Arrow LR");
                    break;
                case 6:
                    strcpy(buffer, "Arrow UD");
                    break;
                case 7:
                    strcpy(buffer, "Page U/D");
                    break;
                case 8:
                    strcpy(buffer, "Erase   ");
                    break;
                default:
                    strcpy(buffer, " -N/A-  ");
                    break;
            }
            break;
    }
}
#endif // OLED_ENABLE