;;;;
;;;;;; Windows/Frames
;;;;

;; control-up, -down, etc. for moving around windows
(condition-case nil (windmove-default-keybindings 'control) (error))
(global-set-key (kbd "M-[ 5 d") 'windmove-left)
(global-set-key (kbd "M-[ 5 C") 'windmove-right)

;; undo windowing changes
(winner-mode 1)

(defun toggle-window-split ()
  "If you have 2 windows, toggle between vertical/horizontal split."
  (interactive)
  (if (= (count-windows) 2)
      (let* ((this-win-buffer (window-buffer))
             (next-win-buffer (window-buffer (next-window)))
             (this-win-edges (window-edges (selected-window)))
             (next-win-edges (window-edges (next-window)))
             (this-win-2nd (not (and (<= (car this-win-edges)
                                         (car next-win-edges))
                                     (<= (cadr this-win-edges)
                                         (cadr next-win-edges)))))
             (splitter
              (if (= (car this-win-edges)
                     (car (window-edges (next-window))))
                  'split-window-horizontally
                'split-window-vertically)))
        (delete-other-windows)
        (let ((first-win (selected-window)))
          (funcall splitter)
          (if this-win-2nd (other-window 1))
          (set-window-buffer (selected-window) this-win-buffer)
          (set-window-buffer (next-window) next-win-buffer)
          (select-window first-win)
          (if this-win-2nd (other-window 1))))))
(define-key ctl-x-4-map "t" 'toggle-window-split)

(defun rotate-windows ()
  "Rotate buffers around the window list."
  (interactive)
  (let* ((wl (window-list))
         (carwl (car wl))
         (cdrwl (cdr wl))
         (bl (map 'list (lambda (x) (window-buffer x)) wl))
         (sl (map 'list (lambda (x) (window-start x)) wl)))
    (add-to-list 'cdrwl carwl t)
    (dolist (tuple (mapcar* 'list cdrwl bl sl))
      (set-window-buffer (car tuple) (cadr tuple))
      (set-window-start (car tuple) (caddr tuple)))))
(define-key ctl-x-4-map "s" 'rotate-windows)

;; fullscreen for mac
(defun eaw-ns-toggle-fullscreen ()
  (interactive)
  (if (fboundp 'ns-toggle-fullscreen)
      (ns-toggle-fullscreen)
    (set-frame-parameter nil 'fullscreen (when (not (frame-parameter nil 'fullscreen)) 'fullboth))))
(defun eaw-fix-fullscreen ()
  (interactive)
  (if (fboundp 'ns-toggle-fullscreen)
      (progn
        (ns-toggle-fullscreen)
        (ns-toggle-fullscreen))
    (set-frame-parameter nil 'tool-bar-lines 1)
    (set-frame-parameter nil 'tool-bar-lines 0)
    ;; first, try to figure out how big a line/column is
    (let (old-width old-height new-width new-height)
      (setq old-width (frame-pixel-width))
      (setq old-height (frame-pixel-height))
      (set-frame-parameter nil 'height (+ 1 (frame-parameter nil 'height)))
      (set-frame-parameter nil 'width (+ 1 (frame-parameter nil 'width)))
      (setq new-width (frame-pixel-width))
      (setq new-height (frame-pixel-height))
      ;; now that we know how big a column is, try to jump immediately to the right size
      (unless (= new-height old-height)
        (set-frame-parameter nil 'height (/ (x-display-pixel-height) (- new-height old-height))))
      (unless (= new-width old-width)
        (set-frame-parameter nil 'width (/ (x-display-pixel-width) (- new-width old-width)))))
    ;; we're probably at the right size, but we may be very far off
    ;; (e.g. different size fonts, etc.). so, first, we'll make sure
    ;; the frame is definitely smaller than the screen
    (while (< (x-display-pixel-width) (frame-pixel-width))
      (set-frame-parameter nil 'width (- (frame-parameter nil 'width) 1)))
    (while (< (x-display-pixel-height) (frame-pixel-height))
      (set-frame-parameter nil 'height (- (frame-parameter nil 'height) 1)))
    ;; now try to make it just slightly bigger
    (while (> (x-display-pixel-width) (frame-pixel-width))
      (set-frame-parameter nil 'width (+ 1 (frame-parameter nil 'width))))
    (while (> (x-display-pixel-height) (frame-pixel-height))
      (set-frame-parameter nil 'height (+ 1 (frame-parameter nil 'height))))
    ;; now shrink it back to the appropriate size
    (if (< (x-display-pixel-width) (frame-pixel-width))
        (set-frame-parameter nil 'width (- (frame-parameter nil 'width) 1)))
    (if (< (x-display-pixel-height) (frame-pixel-height))
        (set-frame-parameter nil 'height (- (frame-parameter nil 'height) 1)))))
(global-set-key (kbd "s-F") 'eaw-ns-toggle-fullscreen)
(global-set-key (kbd "s-f") 'eaw-fix-fullscreen)
(global-set-key [C-s-268632070] 'eaw-ns-toggle-fullscreen)
(global-set-key (kbd "C-s-f") 'eaw-ns-toggle-fullscreen)
;; on mac, don't pop up a frame when using mac UI to open a file
(setq ns-pop-up-frames nil)

;; cycling through frames is annoying when I know where I want to go
(define-key ctl-x-5-map "j" 'select-frame-by-name)

;; changing all other frames to select a different buffer
(defun eaw-select-buffer-other-frames (&optional buffer)
  (interactive)
  (let ((buf (get-buffer-create (or buffer "*scratch*"))))
    (set-buffer-major-mode buf)
    (dolist (frm (frame-list))
      (unless (eq (selected-frame) frm)
        (with-selected-frame frm
          (delete-other-windows)
          (switch-to-buffer buf))))))
(define-key ctl-x-5-map "s" 'eaw-select-buffer-other-frames)

;; a better command to be bound to C-x o
(defun other-window-repeat (COUNT &optional no-repeat)
  "Calls other-window.  If a multiple key sequence was used to
 call this then the last key can be used on its own to repeat
 this, like kmacro-call-macro."
  (interactive "p")
  (let ((repeat-key (and (null no-repeat)
                         (> (length (this-single-command-keys)) 1)
                         last-input-event))
        repeat-key-str
        (nxt t))
    (other-window COUNT)
    (when repeat-key
      (setq repeat-key-str (format-kbd-macro (vector repeat-key) nil)))
    (while repeat-key
      (message "(Type %s to keep cycling)" repeat-key-str)
      (if (equal repeat-key (read-event))
          (progn
            (clear-this-command-keys t)
            (other-window COUNT)
            (setq last-input-event nil))
        (setq repeat-key nil)))
    (when last-input-event
      (clear-this-command-keys t)
      (setq unread-command-events (list last-input-event)))))
(define-key ctl-x-map "o" 'other-window-repeat)

;; no menu bar, scroll bar, tool bar, tooltips, or fringe
(if (fboundp 'tooltip-mode)
    (tooltip-mode -1))
(menu-bar-mode -1)
(if (fboundp 'scroll-bar-mode)
    (scroll-bar-mode -1))
(if (fboundp 'tool-bar-mode)
    (tool-bar-mode -1))
(if (fboundp 'set-fringe-mode)
    (set-fringe-mode 0))

;; show matching parenthesis
(show-paren-mode 1)
;; disable transient mark mode
(transient-mark-mode -1)
;; don't make the cursor blink
(blink-cursor-mode -1)

      ;; scroll one line at a time, rather than a whole page
(setq scroll-conservatively 4
      ;; maintain cursor position when paging up/down
      scroll-preserve-screen-position t
      ;; don't truncate long lines in split windows
      truncate-partial-width-windows nil)

(provide 'ew-window)