#lang racket/base
(require racket/class
         (planet clements/sxml2:1)
         "private/sxml.rkt")
(provide atom<%>
         atom)
(define atom<%>
    (interface ()
    is-feed?         get-sxml         get-raw-sxml     get-id           get-title        get-updated      get-link         get-raw-link     get-entries      get-raw-entries     get-tag-value       ))
(define atom%
  (class* object% (atom<%>)
    (init-field sxml)
    (define root
      (cond [(and (pair? sxml) (memq (car sxml) '(atom:feed atom:entry))) sxml]
            [else (car* ((sxpath '((*or* atom:feed atom:entry))) sxml))]))
    (unless root (error 'atom% "invalid Atom document: ~e" sxml))
    (super-new)
    (define/public (is-feed?)
      (eq? 'atom:feed (sxml:element-name root)))
    (define/public (get-sxml) root)
    (define/public (get-raw-sxml) sxml)
    (define/public (get-id)
      (get1 'atom:get-id 'atom:id))
    (define/public (get-title)
      (get1 'atom:get-title 'atom:title))
    (define/public (get-updated)
      (get1 'atom:get-updated 'atom:updated))
    (define/public (get-link rel [default not-given])
      (let ([result ((sxpath `((atom:link (@ rel (equal? ,rel))) @ href *text*)) root)])
        (cond [(pair? result) (car result)]
              [else (do-default default (error 'atom:get-link "link ~s not found" rel))])))
    (define/public (get-raw-link rel [default not-given])
      (let ([result ((sxpath `((atom:link (@ rel (equal? ,rel))))) root)])
        (cond [(pair? result) (car result)]
              [else (do-default default (error 'atom:get-raw-link "link ~s not found" rel))])))
    (define/public (get-entries)
      (for/list ([entry (in-list (get-raw-entries))])
        (new atom% (sxml entry))))
    (define/public (get-raw-entries)
      ((sxpath '(atom:entry)) root))
    (define/public (get-tag-value tag [default not-given])
      (get1 'atom:get-tag-value tag default))
    
    (define/private (get1 who tag [default not-given])
      (let ([result ((sxpath `(,tag *text*)) root)])
        (cond [(pair? result) (car result)]
              [else (do-default default (error who "element `~a' not found" tag))])))
    ))
(define (car* x)
  (and (pair? x) (car x)))
(define (atom sxml)
  (new atom% (sxml sxml)))