;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; generic functions

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; open org agenda in top side window
; BUGGED AND UNUSED, agenda does NOT work properly in side windows
(defun kmn/org-agenda-on-top ()
  (defvar parameters
    '(window-parameters . ((no-other-window . t)
                           (no-delete-other-windows . t))))

  (setq fit-window-to-buffer-horizontally t)
  (setq window-resize-pixelwise t)

  (interactive)
  (display-buffer-in-side-window
   (get-buffer "*Org Agenda*") `((side . top) (slot . 0)
            (window-width . fit-window-to-buffer)
            (preserve-size . (t . nil)) , parameters))
)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; open dired with default directory in left side window
(defun kmn/dired-directory-on-left (&optional dir_path no-win no-del-o-win slot-num)
  (defvar parameters
    '(window-parameters . ((no-other-window . ,(or no-win (setq no-win t)))
                           (no-delete-other-windows . ,(or no-del-o-win (setq no-del-o-win t))))))

  (setq fit-window-to-buffer-horizontally t)
  (setq window-resize-pixelwise t)

  "Display `default-directory' in side window on left, hiding details."
  (interactive)
  (let ((buffer (dired-noselect (or dir_path (setq dir_path default-directory)))))
    (with-current-buffer buffer (dired-hide-details-mode t))
    (display-buffer-in-side-window
     buffer `((side . left) (slot . ,(or slot-num (setq slot-num -1)))
              (window-width . fit-window-to-buffer)
              , parameters)
    )
  )
)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; open eshell in left side window
(defun kmn/eshell-on-left (&optional shell-directory no-win no-del-o-win slot-num)
  (defvar parameters
    '(window-parameters . ((no-other-window . ,(or no-win (setq no-win t)))
                           (no-delete-other-windows . ,(or no-del-o-win (setq no-del-o-win t))))))

  (setq fit-window-to-buffer-horizontally t)
  (setq window-resize-pixelwise t)
  (setq default-directory (or shell-directory (setq shell-directory default-directory)))

  (interactive)
  (let ((buffer (eshell)))
    (display-buffer-in-side-window
     buffer `((side . left) (slot . ,(or slot-num (setq slot-num -1)))
              (window-width . fit-window-to-buffer)
              , parameters)
    )
  )
)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; open eww in right side window
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; open eww in right side window
(defun kmn/eww-on-right (url &optional no-win no-del-o-win slot-num)
  (defvar parameters
    '(window-parameters . ((no-other-window . ,(or no-win (setq no-win t)))
                           (no-delete-other-windows . ,(or no-del-o-win (setq no-del-o-win t))))))

  (setq fit-window-to-buffer-horizontally t)
  (setq window-resize-pixelwise t)

  (interactive)
  (eww url)
  (let ((buffer (current-buffer)))
    (previous-buffer)
    (display-buffer-in-side-window
     buffer `((side . right) (slot . ,(or slot-num (setq slot-num -1)))
              (window-width . fit-window-to-buffer)
              , parameters)
    )
  )
)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; open text-mode scratch in right side window
(defun kmn/scratch-text-on-right ()
  (defvar parameters
    '(window-parameters . ((no-other-window . t)
                           (no-delete-other-windows . t))))

  (setq fit-window-to-buffer-horizontally t)
  (setq window-resize-pixelwise t)

  "Display `default-directory' in side window on left, hiding details."
  (interactive)
  (let ((buffer (scratch 'text-mode)))
    (display-buffer-in-side-window
     buffer `((side . right) (slot . -1)
              (window-width . fit-window-to-buffer)
              , parameters)
    )
  )
)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; open text-mode scratch in right side window
(defun kmn/scratch-prompt-on-right ()
  (defvar parameters
    '(window-parameters . ((no-other-window . t)
                           (no-delete-other-windows . t))))

  (setq fit-window-to-buffer-horizontally t)
  (setq window-resize-pixelwise t)

  "Display `default-directory' in side window on left, hiding details."
  (interactive)
  (let ((buffer (scratch (let ((current-prefix-arg t)) (scratch--buffer-querymode)))))
    (display-buffer-in-side-window
     buffer `((side . right) (slot . -1)
              (window-width . fit-window-to-buffer)
              , parameters)
    )
  )
)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; quick reference notes as a pop up window
(defun kmn/popwin-quick-ref ()
  (interactive)
  (when (eq system-type 'windows-nt)
    (popwin:find-file "~/org/_quick_reference.org"))
  (when kmn/is-termux
    (popwin:find-file "~/storage/shared/org/_quick_reference.org")))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; modern home/end via C-a and C-e
(defun kmn/smart-beginning-of-line ()
  "Move point to `beginning-of-line'. If repeat command it cycle
position between `back-to-indentation' and `beginning-of-line'."
  (interactive "^")
  (if (eq last-command 'smart-beginning-of-line)
    (if (= (line-beginning-position) (point))
      (back-to-indentation)
      (beginning-of-line))
    (back-to-indentation)))

(defun kmn/smart-end-of-line ()
  "Move point to `end-of-line'. If repeat command it cycle
position between last non-whitespace and `end-of-line'."
  (interactive "^")
  (if (and (eq last-command 'kmn/smart-end-of-line)
        (= (line-end-position) (point)))
    (skip-syntax-backward " " (line-beginning-position))
    (end-of-line)))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; function to kill all non special, non active buffers
(defun kmn/kill-other-buffers ()
  "Kill all buffers but the current one. Don't mess with special buffers. Kill dired buffers"
  (interactive)
  ; dired buffer cleanup
  (mapc
    (lambda (buffer) 
      (when (eq 'dired-mode (buffer-local-value 'major-mode buffer)) 
        (kill-buffer buffer))) 
    (buffer-list))
  ; non special buffer cleanup
  (dolist (buffer (buffer-list))
    (unless (or (eql buffer (current-buffer)) (not (buffer-file-name buffer)))
      (kill-buffer buffer))))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; find/replace all (interactive)
(defun kmn/query-replace-region-or-from-top ()
  "If marked, query-replace for the region, else for the whole buffer (start from the top)"
  (interactive)
  (progn
    (let ((orig-point (point)))
      (if (use-region-p)
          (call-interactively 'query-replace)
        (save-excursion
          (goto-char (point-min))
          (call-interactively 'query-replace)))
      (message "Back to old point.")
      (goto-char orig-point))))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; dock current buffer in given side panel
(defun kmn/dock-current-buffer-on-side (selected_side)
  (defvar parameters
    '(window-parameters . ((no-delete-other-windows . t))))

  (setq fit-window-to-buffer-horizontally t)
  (setq window-resize-pixelwise t)

  "Display `default-directory' in side window on left, hiding details."
  (interactive)
  (let ((buffer (current-buffer)))
    (display-buffer-in-side-window
     buffer `((side . ,selected_side) (slot . -1)
              (window-width . fit-window-to-buffer)
              , parameters)
    )
  )
)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; dock current buffer on right
(defun kmn/dock-current-buffer-on-right ()
  (interactive)
  (kmn/dock-current-buffer-on-side 'right)
)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; dock current buffer on right
(defun kmn/dock-current-buffer-on-left ()
  (interactive)
  (kmn/dock-current-buffer-on-side 'left)
)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; dock current buffer on right
(defun kmn/dock-current-buffer-on-top ()
  (interactive)
  (kmn/dock-current-buffer-on-side 'top)
)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; dock current buffer on right
(defun kmn/dock-current-buffer-on-bottom ()
  (interactive)
  (kmn/dock-current-buffer-on-side 'bottom)
)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; perform days math on a date string
(defun kmn/date-string-days-math (date-string days-to-subtract)
(format-time-string "%Y-%m-%d" 
  (encode-time 
    (decoded-time-add (parse-time-string date-string) (make-decoded-time :day days-to-subtract))
  )
))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; subtract 7 days from a date string
(defun kmn/date-string-minus-seven-days (date-string)
  (kmn/date-string-days-math date-string -7)
)

; subtract 3 days from a date string
(defun kmn/date-string-minus-three-days (date-string)
  (kmn/date-string-days-math date-string -3)
)
