;;; kkk-generate.el --- Generate Function            -*- lexical-binding: t; -*-

;; Copyright (C) 2023  Vinicius Teshima <vini.tes@pm.me>

;; Author: Vinicius Teshima <vini.tes@pm.me>

;; 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 for more details.

;; You should have received a copy of the GNU General Public License
;; along with this program.  If not, see <https://www.gnu.org/licenses/>.

;;; Commentary:

;; Function to generate things

;;; Code:

(defgroup kkk-generate nil
  "Group of generate function."
  :group 'files)

(defun kkk-generate-java-getter nil
  "Generate Getters from attribute definition.

It will parse until it finds an empty line."
  (interactive)
    (while (not (string-empty-p (thing-at-point 'line 't)))
      (let* ((parsed_line (cdr (split-string (thing-at-point 'line 't))))
             (type (pop parsed_line))
             (name (car (split-string (pop parsed_line) ";") ))
             (beg (point)))
        (progn
          (kill-whole-line 0)
          (insert "public " type " get" (upcase-initials name) "() {\n"
                  "return this." name ";\n"
                  "}\n")
          (indent-region beg (point))
          (line-move 1)))))

(defun kkk-generate-java-setter nil
  "Generate Setters from attribute definition.

It will parse until it finds an empty line."
  (interactive)
    (while (not (string-empty-p (thing-at-point 'line 't)))
      (let* ((parsed_line (cdr (split-string (thing-at-point 'line 't))))
             (type (pop parsed_line))
             (name (car (split-string (pop parsed_line) ";") ))
             (beg (point)))
        (progn
          (kill-whole-line 0)
          (insert "public void set" (upcase-initials name) "(" type " " name ") {\n"
                  "this." name " = " name ";\n"
                  "}\n")
          (indent-region beg (point))
          (line-move 1)))))

(defun list-get-odd (LIST)
  "Return all the odd index items from LIST."
  (if (listp LIST)
      (let ((ret '()))
        (while (not (null LIST))
          (push 'ret (car LIST))
          (setq LIST (cddr LIST))
          )
        ret)))

(defun list-get-even (LIST)
  "Return all the even index items from LIST."
  (if (listp LIST)
      (list-get-odd (cdr LIST))))

(defun list-str-rm-last-chr (LIST)
  "LIST is a list."
  (let ((ret '()))
    (while (not (null LIST))
      (push 'ret (substring (car LIST) 0 -1))
      (setq LIST (cdr LIST)))
    ret))

(defun kkk-generate-java-constructor (BEG END)
  "Generate Constructor from attribute definition.

BEG is the beginning of the region.
END is the end of the region.

It will parse until it finds an empty line."
  (interactive "r")
  (let* ((tmp_args  (split-string (buffer-substring-no-properties BEG END)))
         (args (remove "protected" (remove "public" (remove "private" tmp_args))))
         (types (list-get-odd args))
         (names (list-str-rm-last-chr (list-get-even args))))
    (if (= (cl-list-length types) (cl-list-length names))
        (progn
          (kill-region BEG END)
          (insert "public TMP(")
          (let ((i 0) (limit (cl-list-length types)))
            (while (< i limit)
              (if (= i (1- limit))
                  (insert (format "%s %s" (nth i types) (nth i names)))
                (insert (format "%s %s, " (nth i types) (nth i names))))
              (setq i (1+ i))))
          (insert ") {\n")
          (let ((i 0) (limit (cl-list-length types)))
            (while (< i limit)
              (insert (format "this.%s = %s;\n" (nth i names) (nth i names)))
              (setq i (1+ i))))
          (insert "}\n"))))
  (indent-region BEG (point)))

(defun kkk-generate-java-mode-keys ()
  "Define my keybinds on java mode."
  (define-key java-mode-map (kbd "C-c g g") 'java-generate-getter)
  (define-key java-mode-map (kbd "C-c g s") 'java-generate-setter)
  (define-key java-mode-map (kbd "C-c g c") 'java-generate-constructor))

;; (add-hook 'java-mode-hook #'define-my-java-mode-keys)

(defun kkk-generate-cpp-getter-definition ()
  "Generate Getters Definition from attribute definition.

It will parse until it finds an empty line."
  (interactive)
  (while (not (string= "\n" (thing-at-point 'line 't)))
    (let* ((parsed_line (split-string
                         (string-replace ";" "" (thing-at-point 'line 't))))
           (type (car parsed_line))
           (name (string-remove-prefix "m_" (cadr parsed_line)))
           (beg (point)))
      (progn
        (kill-whole-line 0)
        (insert type " get" (upcase-initials name) "();")
        (indent-region beg (point))
        (line-move 1)))))

(defun kkk-generate-cpp-setter-definition ()
  "Generate Getters Definition from attribute definition.

It will parse until it finds an empty line."
  (interactive)
  (while (not (string= "\n" (thing-at-point 'line 't)))
    (let* ((parsed_line (split-string
                         (string-replace ";" "" (thing-at-point 'line 't))))
           (type (car parsed_line))
           (name (string-remove-prefix "m_" (cadr parsed_line)))
           (beg (point)))
      (progn
        (kill-whole-line 0)
        (insert "void set" (upcase-initials name) "(" type " " name ");")
        (indent-region beg (point))
        (line-move 1)))))

(defun kkk-generate-cpp-getter-implementation ()
  "Generate Getters Definition from attribute definition.

class type name;

It will parse until it finds an empty line."
  (interactive)
  (while (not (string= "\n" (thing-at-point 'line 't)))
    (let* ((parsed_line (split-string
                         (string-replace ";" "" (thing-at-point 'line 't))))
           (class (car parsed_line))
           (type (cadr parsed_line))
           (name (string-remove-prefix "m_" (caddr parsed_line)))
           (beg (point)))
      (progn
        (kill-whole-line 0)
        (insert type " " class "::get" (upcase-initials name)
                "() {\nreturn this->m_" name ";\n}")
        (indent-region beg (point))
        (line-move 1)))))

(defun kkk-generate-cpp-setter-implementation ()
  "Generate Getters Definition from attribute definition.

class type name;

It will parse until it finds an empty line."
  (interactive)
  (while (not (string= "\n" (thing-at-point 'line 't)))
    (let* ((parsed_line (split-string
                         (string-replace ";" "" (thing-at-point 'line 't))))
           (class (car parsed_line))
           (type (cadr parsed_line))
           (name (string-remove-prefix "m_" (caddr parsed_line)))
           (beg (point)))
      (progn
        (kill-whole-line 0)
        (insert "void " class "::set" (upcase-initials name)
                "(" type " " name ") {\nthis->m_" name " = " name ";\n}")
        (indent-region beg (point))
        (line-move 1)))))

(defun kkk-generate-cpp-contructor-definition ()
  "Generate Constructor from attribute definition.

TODO: IMPLEMENT;"
  (interactive) (message "TODO: IMPLEMENT"))

(defun kkk-generate-cpp-contructor-implementation ()
  "Generate Constructor from attribute definition.

TODO: IMPLEMENT;"
  (interactive) (message "TODO: IMPLEMENT"))

(defun kkk-generate-cpp-mode-keys ()
  "Define my keybinds on c++ mode"
  (define-key c++-mode-map (kbd "C-c g i g")
	      #'kkk-generate-cpp-getter-implementation)
  (define-key c++-mode-map (kbd "C-c g i s")
	      #'kkk-generate-cpp-setter-implementation)
  (define-key c++-mode-map (kbd "C-c g i c")
	      #'kkk-generate-cpp-contrutor-implementation)
  (define-key c++-mode-map (kbd "C-c g d g")
	      #'kkk-generate-cpp-getter-definition)
  (define-key c++-mode-map (kbd "C-c g d s")
	      #'kkk-generate-cpp-setter-definition)
  (define-key c++-mode-map (kbd "C-c g i c")
	      #'kkk-generate-cpp-contrutor-definition))

;; (add-hook 'c++-mode-hook #'kkk/keybinds/cpp/generators)

(provide 'kkk-generate)
;;; kkk-generate.el ends here
