(module mred-state mzscheme
  (require (lib "class.ss")
           (lib "struct.ss")
           (lib "mred.ss" "mred")
           "utilities.ss"
           "structures.ss"
           "rope.ss")
  
  (provide MrEd-state% MrEd-state<%>)
  
                        
  
    (define MrEd-state<%>
    (interface ()
      
                  pull-world
      
                  push-world))
  
  
        
  (define MrEd-state%
    (class* object% (MrEd-state<%>)
      
      (super-instantiate ())
      
                        
                              
      (init window-text-init)
      (define window-text window-text-init)
      
      
      
      
      
                        
                  (define (get-rope)
        (send window-text diva:-get-rope))
      
                  (define (update-text rope)
        (send window-text diva:-update-text rope))
      
      
                        
      
                        
                  (define (get-cursor-position)
        (index->pos (send window-text get-start-position)))
      
                  (define (set-cursor-position pos)
        (send window-text diva:set-selection-position (pos->index pos)))
      
      
                                    (define (set-selection pos len)
        (if (<= 0 len)
            (begin (send window-text set-position
                         (pos->index pos)
                         (+ len (pos->index pos))
                         #f #f 'local)
                   (send window-text scroll-to-position
                         (pos->index pos)
                         #f
                         (+ len (pos->index pos))
                         'start))
            (set-selection (+ pos len) (- len))))
      
                  (define (get-selection-len)
        (let ([start-pos (send window-text get-start-position)]
              [end-pos   (send window-text get-end-position)])
          (- end-pos start-pos)))
      
      
                        
      (define (get-mark-position)
        (index->pos (send window-text diva:-get-mark-start-position)))
      
      (define (get-mark-length)
        (let ([mark-start-pos (send window-text diva:-get-mark-start-position)]
              [mark-end-pos   (send window-text diva:-get-mark-end-position)])
	  (- mark-end-pos mark-start-pos)))
      (define (set-mark pos len)
        (if (>= len 0)
	    (send window-text diva:-set-mark (pos->index pos) (+ (pos->index pos) len))
	    (set-mark (+ pos len) (- len))))
                        
                                    (define/public (pull-world original-world)
        (update-world-path
         (update-world-mark 
          (update-world-select 
                                 (update-world-text original-world)))))
      
      
                        (define (update-world-path original-world)
        (copy-struct World original-world
                     [World-path (send window-text get-filename)]))
      
                        (define (update-world-text original-world)
        (cond
          [(rope=? (World-rope original-world) (get-rope))
                                 (copy-struct World original-world
                        [World-rope (get-rope)]
                        [World-syntax-list/lazy
                         (World-syntax-list/lazy original-world)])]
          [else
           (copy-struct World original-world
                        [World-rope (get-rope)]
                        [World-syntax-list/lazy #f])]))
      
      
                        (define (update-world-select original-world)
        (let*-values
            ([(p l) (values (get-cursor-position) (get-selection-len))]
             [(stop-extending)
              (or clear-extension
                  (not (and
                        (= p (World-cursor-position original-world))
                        (= l (World-selection-length original-world)))))])
          (copy-struct World original-world
                       [World-cursor-position (get-cursor-position)]
                       [World-selection-length (get-selection-len)]
                       [World-extension (if stop-extending #f (World-extension original-world))])))
      
            (define (update-world-mark original-world)
        (if (World-extension original-world)
            original-world
            (copy-struct World original-world
                         [World-mark-position     (get-mark-position)]
                         [World-mark-length (get-mark-length)])))
      
      
      (define clear-extension #f)
                                    (define/public (push-world world)
        (unless (rope=? (World-rope world) (get-rope))
          (update-text (World-rope world)))
        (set-selection (World-cursor-position world) (World-selection-length world))
        (cond [(World-extension world)
               (let ([e (World-extension world)])
                 (set-mark (extension-puck e)
                           (extension-puck-length e))
                 (send window-text scroll-to-position
                       (extension-puck e)
                       #f
                       (+ (extension-puck e) (extension-puck-length e))
                       'none)
                 (set! clear-extension #f)
                 (send window-text diva:-insertion-after-set-position-callback-set
                       (lambda ()
                         (send window-text diva-message "")
                         (set! clear-extension #t)
                         (set-mark 1 0))))]
              [else
               (set-mark (World-mark-position world) (World-mark-length world))
               (send window-text diva:-insertion-after-set-position-callback-set
                     (lambda () (void)))])
        
        (send window-text diva-message (World-success-message world))))))