(eval-when (:compile-toplevel :execute :load-toplevel)
  (register-namespace "alz:" "http://www.alzforum.org/res/com/ant#")
  (register-namespace "reagent:" "http://www.w3.org/2001/sw/hcls/ontologies/reagent.owl#"))

(define-ontology reagent (:base "http://www.w3.org/2001/sw/hcls/ontologies/reagent.owl")
  (class !Reagent :partial)
  (class !Antibody :partial !Reagent)

  ;; antibody clonality
  (value-partition '(!AntibodyClonality !PolyclonalAntibody !MonoclonalAntibody))
  (object-property !hasClonality :functional  (domain !Antibody)  (range  !AntibodyClonality))

  ;; isotype
  (value-partition
   '(!AntibodyImmunoglobulin 
     (!IgG !IgG1 (!IgG2 !IgG2a !IgG2b !IgG2c) !IgG3) !IgM !IgY))

  (value-partition '(!AntibodyHeavyChain !KappaChain !LambaChain))
 
  ;; methods
;;  (define-alz-methods)

  ;; sample preparation

  (value-partition '(!ImmunoAssaySamplePreparation 
		     !CellSmearSample
		     !CellsSample
		     !VibratomeSectionsSample
		     !ParaffinSectionsSample
		     !FrozenSectionsSample))
		     

  ;; database fields 
  (annotation-property !hasEpitopeDescription)
  (annotation-property !hasSpecificityDescription)
  (annotation-property !hasHostDescription)
  (annotation-property !hasReactivityDescription)
  (annotation-property !hasCompanyDescription)
  (annotation-property !alz:hasAntibodyId)
  (annotation-property !alz:hasAntigenClass)

  )


(defun foreach-antibody-entry (function)
  (with-open-file (f "hcls/biordf/reagents/antibody-db-dump-2006-03.txt")
    (let ((headers (mapcar (lambda(header) (intern (string-upcase header) 'keyword))
			   (split-at-regex (read-line f) "\\t"))))
      (loop for line = (read-line f nil :eof)
	   until (eq line :eof)
	   for fields = (split-at-regex line "\\t")
	 do 
	   (funcall function (mapcar 'cons headers fields))))))


;;   (class !Supplier :partial)
;;   (class !Manufacturer :partial !supplier)
;;   (class !Supplier :partial !supplier)
;;   (class !epitopeDescription :partial)
;;   (class !SequenceRange :partial !epitopeDescription)
;;   (datatype-property !fromSequencePosition range(xsd:int))
;;   (datatype-property !toSequencePosition range(xsd:int))
;;   (class !ProteinSequenceRange  :partial !SequenceRange)
;;   (object-property !ofProtein domain(!ProteinSequenceRange) range(!Protein))
;;   (class !method :partial)

;; (("antibodyID" "626")
;;  ("antigenID" "Bcl") ; class. (does this include families?)
;;  ("datasheet" "trans610746.asp")
;;  ("datasheetLinkText" "Bcl-X")
;;  ("externalLink" "1")
;;  ("clonalityID" "monoclonal")
;;  ("cloneNum" "44")
;;  ("antigenInfo" "  IgG1")
;;  ("companyName" "BD Biosciences PHARMINGEN") ;; http://www.bdbiosciences.com/index.shtml
;;  ("distributorInfo" "Formerly Transduction") ;; entrez 598 http://www.ncbi.nlm.nih.gov/entrez/query.fcgi?db=gene&cmd=Retrieve&dopt=full_report&list_uids=598
;;  ("epitope" "aa. 18-233 of human Bcl-XL") 
;;  ("host" "mouse")
;;  ("hostFastOutput" "monoclonal mouse")
;;  ("hostExtraInfo" "BSA, azite")
;;  ("methodFastOutput" "IF, IH, WB") ;; http://www.alzforum.org/res/com/ant/glossary.asp
;;  ("methodExtraInfo" "")
;;  ("specificity" "Bcl-X, 26kDa")
;;  ("reactivityFastOutput" "human, rat, mouse")
;;  ("reactivityExtrainfo" "NULL") 
;;  ("fromWhoID" "Manufacturers"))

;;   (individual !monoclonal (type !MonoclonalAntibody))
;;   (individual !polyclonal (type !PolyClonalAntibody))

;;   (individual !alzant:626 !Antibody
;; 	      (value !hasClonality !monoclonal)
;; 	      (value !
  
;;   )



;; (loop for a in 
;;        (map 'list #"toString" (#"split" "antibodyID	antigenID	datasheet	datasheetLinkText	externalLink	clonalityID	cloneNum	antigenInfo	companyName	distributorInfo	epitope	host	hostFastOutput	hostExtraInfo	methodFastOutput	methodExtraInfo	specificity	reactivityFastOutput	reactivityExtrainfo	fromWhoID"
;; 				 "\\t"))
;;      for b in 

;;      (map 'list #"toString" (#"split" "626	Bcl	trans610746.asp	Bcl-X	1	monoclonal	44	  IgG1	BD Biosciences PHARMINGEN	Formerly Transduction	aa. 18-233 of human Bcl-XL	mouse	monoclonal mouse	BSA, azite	IF, IH, WB		Bcl-X, 26kDa	human, rat, mouse	NULL	Manufacturers"))
;;      collect (list a b))


;; (("antibodyID" "626")
;;  ("antigenID" "Bcl") ; class. (does this include families?)
;;  ("datasheet" "trans610746.asp")
;;  ("datasheetLinkText" "Bcl-X")
;;  ("externalLink" "1")
;;  ("clonalityID" "monoclonal")
;;  ("cloneNum" "44")
;;  ("antigenInfo" "  IgG1")
;;  ("companyName" "BD Biosciences PHARMINGEN") ;; http://www.bdbiosciences.com/index.shtml
;;  ("distributorInfo" "Formerly Transduction") ;; entrez 598 http://www.ncbi.nlm.nih.gov/entrez/query.fcgi?db=gene&cmd=Retrieve&dopt=full_report&list_uids=598
;;  ("epitope" "aa. 18-233 of human Bcl-XL") 
;;  ("host" "mouse")
;;  ("hostFastOutput" "monoclonal mouse")
;;  ("hostExtraInfo" "BSA, azite")
;;  ("methodFastOutput" "IF, IH, WB") ;; http://www.alzforum.org/res/com/ant/glossary.asp
;;  ("methodExtraInfo" "")
;;  ("specificity" "Bcl-X, 26kDa")
;;  ("reactivityFastOutput" "human, rat, mouse")
;;  ("reactivityExtrainfo" "NULL") 
;;  ("fromWhoID" "Manufacturers"))


(define-ontology alzantibodies  (:base "http://www.w3.org/2001/sw/hcls/ontologies/reagent.owl"
				     :includes '(reagent))
  (let ((individuals nil)
	(count 0))
    (block limit
      (foreach-antibody-entry 
       (lambda(entry)
	 (let ((lastfield nil) (lastvalue nil))
	   (flet ((field (field) 
		    (if (eq field lastfield)
			lastvalue
			(setq lastvalue
			      (let ((value (cdr (assoc field entry))))
				(if (and (char= (char value 0) #\")
					 (char= (char value (1- (length value))) #\"))
				    (setq value (subseq value 1 (- (length value) 2))))
				(if (or (equal value "NULL") (equal value "&nbsp;"))
				    nil
				    (progn
				      (#"replaceAll" (#"replaceAll" value "&" "&amp;") "\"" "%22"))))))))
;	   (when (> (incf count)  2000)
;	     (return-from limit nil))
	   (let* ((name (make-uri-base-relative (format nil "antibody-~a"  (field :antibodyid)) "alz:"))
		  (individual 
		   (individual name 
			       (annotation !alz:hasAntibodyId (field :antibodyid))
			       (and (field :epitope)
				    (annotation !hasEpitopeDescription (field :epitope)))
			       (and (field :specificity)
				    (annotation !hasSpecificityDescription  (field :specificity)))
			       (and 
				(field :hostfastoutput) 
				(annotation !hasHostDescription 
					    (format nil "~a~a" 
						    (field :hostfastoutput) 
						    (if (field :hostExtraInfo)
							(format nil " (~a)" (field :hostExtraInfo))
							""))))
			       (and 
				(field :reactivityfastoutput)
				(annotation !hasReactivityDescription
					    (format nil "~a~a" 
						    (field :reactivityfastoutput) 
						    (if (field :reactivityextrainfo)
							(format nil " (~a)" (field :reactivityextrainfo))
							""))))
			       (and (field :companyname)
				    (annotation !hasCompanyDescription  (field :companyname)))
			       (annotation !alz:hasAntigenClass (field :antigenId))
			       (type !Antibody))))
	     (push individual individuals)))))))
    individuals))


(defun ant (&optional limit)
  (let ((count 0)
	(unknowns nil))
    (foreach-antibody-entry 
     (lambda (entry)
       (if (and limit (> (incf count)  limit))
	   (return-from ant unknowns)
	   (progn
	     ;;(setq unknowns (union unknowns (second (multiple-value-list (parse-methods entry))) :test 'equal))
	     ;;(pushnew (parse-antigen-info entry) unknowns :test 'equalp)
	     (pushnew (parse-specificity entry) unknowns :test 'equalp)
	     ))))
    unknowns))

(defun all-matches (string regex &rest which)
  (let ((matcher (#"matcher" (#"compile" 'java.util.regex.pattern regex) string)))
    (loop while (#"find" matcher) 
       collect (loop for g in which collect
	     (#"group" matcher g)))))
  
(defun parse-methods (entry)
  (let ((known (test))
	(unknowns nil))
    (let* ((methods (cdr (assoc :methodfastoutput entry)))
	   (cleaned (#"replaceAll" methods "<.{0,1}nobr>"  "")))
      (setq cleaned (#"replace" cleaned "\"" ""))
      (let ((composites (all-matches cleaned  "(I.)\\((.*?)\\)" 0 1 2)))
	(loop for (got) in composites
	   do (setq cleaned (#"replace" cleaned got  "")))
	(setq cleaned (split-at-regex cleaned "\\s*,\\s*"))
	(setq cleaned (remove "NULL" cleaned :test 'equalp))
	(loop for (got prefix which) in composites
	   for specifics = (split-at-regex which "\\s*,\\s*")
	   do (loop for specific in specifics
		 do (push (format nil "~a(~a)" prefix specific) cleaned)))
	(loop for one in cleaned 
	   when (not (find one known :test 'equalp))
	   do 
	   (pushnew one unknowns :test 'equal))))
    (values cleaned unknowns)))

;; http://www.antibodyresource.com/educational.html
;; http://nhpreagents.bidmc.harvard.edu/NHP/default.aspx
;; http://www.keithbahjat.com/abcxr/
;; http://www.hiv.lanl.gov/content/immunology/search_help.html
;; http://www.google.com/search?client=safari&rls=en&q=antibody+database&ie=UTF-8&oe=UTF-8
;; http://www.cellnucleus.com/antibody.htm
;; http://www.antibodyresource.com/findantibody.html
;; http://www.linscottsdirectory.com/
;; http://researchlink.labvelocity.com/products/index.jhtml;$sessionid$UGVHAQYAAAQXCQBICNVBNWQ?nodeId=1017&path=0

;; http://en.wikipedia.org/wiki/Immunoglobulin
;; http://en.wikipedia.org/wiki/Immunoglobulin#IgG
;; IgG: 1,2a,2b,3 - can be annotated kappa
;; http://en.wikipedia.org/wiki/Immunoglobulin#IgM
;; IgM
;; IgY (chicken)
;; 954 is kappa
;; 955 is lambda
;; RMAB recombinant monoclonal antibody (rmAb) http://www.ncbi.nlm.nih.gov/entrez/query.fcgi?cmd=Retrieve&db=PubMed&list_uids=1751781&dopt=Abstract (only one example in altz)

(defparameter *isotype-noise-pattern* (load-time-value (#"compile" 'java.util.regex.pattern "(<br>)|(&amp;)|(&nbsp;)|([lL]igand)|(^[ \"]*)|([ \"]*$)|(<\\/>)|((?i)<.{0,1}sub[>.])")))

(defun parse-antigen-info (entry)
  (let ((antigenInfo (cdr (assoc :antigenInfo entry))))
    (setq antigenInfo (#"replaceAll" (#"matcher" *isotype-noise-pattern* antigenInfo) "")) ; noise
    (setq antigenInfo (#"replaceAll" antigenInfo "^\\s*" ""))
    (setq antigenInfo (#"replaceAll" antigenInfo "[ ,]{0,1}&#954;" " kappa"))
    (setq antigenInfo (#"replaceAll" antigenInfo "954" " kappa"))
    (setq antigenInfo (#"replaceAll" antigenInfo "[ ,]{0,1}&#(955|923);" " lambda"))
    (setq antigenInfo (#"replaceFirst" antigenInfo "^.*?(?=[Ii][Gg].*)" ""))
    (setq antigenInfo (#"replaceAll" antigenInfo "[;></-)]|(&#)" ""))
    (setq antigenInfo (#"replaceAll" antigenInfo "k$" " kappa"))
    (unless (or (equal antigenInfo "NULL")
		(not (#"matches" antigenInfo "(?i).*ig.*" )))
      antigenInfo)))

(defun parse-specificity (entry)
  (let ((specificity (cdr (assoc :specificity entry))))
    (#"replaceAll" specificity "^\\s*"  "")
    (#"replaceAll" specificity "\\s*$"  "")
    (if (not (find #\space specificity :test 'char=))
	specificity)))

(defun parse-epitopes (&aux (count 0) (rangecount 0) (numbercount 0))
  (with-open-file (f "parsed-epitopes.txt" :direction :output :if-exists :supersede :if-does-not-exist :create)
  (foreach-antibody-entry 
   (lambda(entry)
     (let ((epitope (cdr (assoc :epitope entry))))
       (setq epitope (#"replaceAll" epitope "^(\\s|\")*"  ""))
       (setq epitope (#"replaceAll" epitope "(\\s|\")*$"  ""))
       (let ((matcher (#"matcher" (#"compile" 'java.util.regex.pattern
					      "(?i)(?:Immunogen\\s*=\\s*){0,1}(.*?)(?:a[.]{0,1}a[.]{0,1}|amino acids|residues|sequence)*\\s*[(]{0,1}(\\d+)[)]{0,1}\\s*(?:-|to)\\s*(\\d+)\\s*(?:of){0,1}\\s*(.*)")
				  epitope)))
	 (if (#"matches" epitope ".*\\d+\\s*(-|to)\\s*\\d+.*")
	     (incf rangecount))
	 (if (#"matches" epitope ".*\\s+\\d+.*")
	     (incf numbercount))
	 (if (#"matches" matcher)
	   (let ((part1 (#"group" matcher 1))
		 (range-start (#"group" matcher 2))
		 (range-end (#"group" matcher 3))
		 (part2 (#"group" matcher 4)))
	     (format f "~a	~a	~a	~a~%" part1 range-start range-end part2)
	     (incf count))
	   (if (#"matches" epitope ".*\\d+\\s*(-|to)\\s*\\d+.*")
	       (print epitope)
	       )))))))
  (values count rangecount numbercount))

;; GO:0019814 immunoglobulin complex

;; !alz:antigenClass

;; !alz:Antibody
;;  !alz:hasIsotype
;;  !alz:hasHeavyChain
;;  !alz:targetsEpitope
;;  !alz:doesNotTargetEpitope
;;  !alz:targetsAntigen 
;;  !alz:derivedFromHostSpecies
;;  !alz:hasClonality
;;  !alz:usedForMethod
;;  !alz:isReactiveInSpecies
;;  !alz:isAvailableFromManufacterer
;;  !alz:hasSpecificationSheet

;; "IgG2a,  IgG2a, IgG1" 
;; "IgM + IgG1" 
;; "IgG2b, IgG1" 
;; "IgGb" 
;; "IgG1c" 
;; "IgG2aIgG2a" 
;; "IgG2a, IgG2b" 
;; "IgG1  IgM" 
;; "IgM & IgG1" 
;; "Ig1" 
;; "IgG1 and IgG2a" 
;; "IgG3* kappa" 
;; "IgG2 lambda2" 
;; "IgG1and IgG2a" 
;; "IgM kappa" 
;; "IgG3 kappa" 
;; "IgY" 
;; "IgG)" 
;; "IgG1 lambda" 
;; "IgG1 kappa, lambda" 
;; "IgG2c kappa" 
;; "IgG1+IgG2a" 
;; "IgG2a, IgG2a, IgG1" 
;; "IgG1 kappa,IgG2a kappa, IgG2a kappa," 
;; "IgG1, kappa" 
;; "IgM" 
;; "IgG2b kappa" 
;; "IgG2a kappa" 
;; "Ig" 
;; "IgG2b" 
;; "IgG2 kappa" 
;; "IgG3" 
;; "IgG2a" 
;; "IgG1" 
;; "IgG" 
;; NIL 
;; "IgG1 kappa" 
