1<?php
2if(!defined('DOKU_INC')) die();
3if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/');
4require_once(DOKU_PLUGIN.'syntax.php');
5
6class syntax_plugin_pubchem extends DokuWiki_Syntax_Plugin {
7  var $ncbi;
8  var $imgCache;
9  var $xmlCache;
10  var $summaryURL='';
11  var $downloadURL='';
12  var $chemProperty = array();
13
14  function __construct(){
15    $this->name = 'pubchem';
16    if (!class_exists('plugin_cache'))
17        @require_once(DOKU_PLUGIN.$this->name.'/classes/cache.php');
18    if (!class_exists('rcsb')||!class_exists('ncbi')||!class_exists('xml'))
19        @require_once(DOKU_PLUGIN.$this->name.'/classes/sciencedb.php');
20    $this->ncbi        = new ncbi();
21    $this->imgCache    = new plugin_cache($this->name,'',"png");
22    $this->xmlCache    = new plugin_cache($this->name,'',"xml.gz");
23    $this->propCache   = new plugin_cache($this->name,'prop','json');
24
25    $this->summaryURL  = 'https://pubchem.ncbi.nlm.nih.gov/summary/summary.cgi?cid=';
26    $this->downloadURL = 'https://pubchem.ncbi.nlm.nih.gov/image/imgsrv.fcgi?t=%s&cid=%s';
27  }
28  function getType(){ return 'substition'; }
29  function getSort(){ return 159; }
30
31  // Connect
32  function connectTo($mode){
33    $this->Lexer->addSpecialPattern('\{\{pubchem>[^}]*\}\}',$mode,'plugin_pubchem');
34  }
35
36  // Handling lexer
37  function handle($match, $state, $pos, Doku_Handler $handler){
38    $match = substr($match,10,-2);
39    return array($state,explode(':',$match));
40  }
41
42/**
43  * Render PubChem image and link
44  */
45  function render($mode, Doku_Renderer $renderer, $data){
46    if ($mode!='xhtml') return false;
47    global $pubchem_cache;
48    if(!is_array($pubchem_cache)) $pubchem_cache=array();
49
50    list($state, $match) = $data;
51    list($cmd,$cid) = $match;
52    $cmd = strtolower($cmd);
53    if(strpos($cid,'|')!==false){
54      list($cid,$title)=explode('|',$cid);
55    }
56    // Commands without CID
57    switch($cmd){
58        case 'searchbox':
59            $renderer->doc .= file_get_contents(DOKU_PLUGIN.$this->name.'/pubchem_search_box.htm').NL;
60            return true;
61        case 'clear':
62            $this->xmlCache->ClearCache();
63            $renderer->doc .= 'Cleared.';
64            return true;
65        case 'remove_dir':
66            $this->xmlCache->RemoveDir();
67            $renderer->doc .= 'Directory cleared.';
68            return true;
69        default:
70            if(!$cid){
71              $renderer->doc.='<div class="plugin_cmd">'.sprintf($this->getLang('plugin_cmd_not_found'),$cmd).'</div>';
72              return true;
73            }
74     }
75    // Commands with CID
76    if (!is_numeric($cid)){
77        $renderer->doc .= sprintf($this->getLang('pubchem_invalid_cid'),$cid);
78        return false;
79    }
80    if ($this->propCache->Exists($cid)){
81      $ext_props = json_decode($this->propCache->GetMediaText($cid),true);
82    }else{
83      $ext_props = $this->getProperties($cid);
84    }
85    $iupac   = array_key_exists('iupac',  $ext_props) ? $ext_props['iupac']:'';
86    $formula = array_key_exists('formula',$ext_props) ? $ext_props['formula']:'';
87    $mw      = array_key_exists('mw',     $ext_props) ? $ext_props['mw']:'';
88    $xlogp   = array_key_exists('xlogp',  $ext_props) ? $ext_props['xlogp']:'';
89    switch($cmd){
90        case 'link':
91            $renderer->doc .= '<a target=_blank ';
92            $renderer->doc .= 'href="'.$this->summaryURL.$cid.'" title="Go to PubChem site" class="pubchem_link">'.$cid.'</a>'.NL;
93            return true;
94        case 'summaryxml':
95            $xml = $this->getPubchemXml($cid);
96            if ($xml===false){return true;}
97            $renderer->doc .= '<pre>'.htmlspecialchars($xml).'</pre>';
98            return true;
99        case 'iupac':
100            $renderer->doc.= $iupac;
101            return true;
102        case 'formula':
103            $renderer->doc.= $formula;
104            return true;
105        case 'mw':
106            $renderer->doc.= $mw;
107            return true;
108        case 'xlogp':
109            $renderer->doc.= $xlogp;
110            return true;
111        default:
112            $mode = $cmd[0]; // s or l
113            $id = $cid.$mode;
114            $filename = $this->imgCache->GetMediaPath($id);
115            if(!is_readable($filename)){
116                $url = sprintf($this->downloadURL,$mode,$cid);
117                io_download($url,$filename);
118            }
119            if(strpos($cmd,'template')!==false){
120                if (empty($pubchem_cache[$cid]['iupac'])){
121                    $this->getProperties($cid);
122                }
123                $renderer->doc.='<div class="left" style="padding:10px;">';
124                $renderer->table_open(2);
125                $this->_name_row($renderer,$cid,$iupac,$title);
126                $this->_row($renderer,$this->getLang('mol_formula'),$formula);
127                $this->_row($renderer,$this->getLang('mol_weight'), $mw);
128                $this->_row($renderer,'LogP',$xlogp);
129                $renderer->table_close();
130                $renderer->doc.='</div><div class="left">';
131                $renderer->doc .= $this->getImageHtml($cid,$mode);
132                $renderer->doc.='</div><div class="clearfix"></div>'.DOKU_LF;
133            }else{
134                $renderer->doc .= $this->getImageHtml($cid,$mode);
135            }
136            return true;
137    }
138    // Command was not found..
139    $renderer->doc.='<div class="plugin_cmd">'.sprintf($this->getLang('plugin_cmd_not_found'),$cmd).'</div>';
140    return true;
141  }
142
143/**
144  * Get PubChem image description
145  */
146  function getImageHtml($cid,$mode){
147        $tag = '<div class="pubchem_imgbox"><a href="'.$this->summaryURL.$cid.'" target=_blank>';
148        $tag .= '<img src = "'.$this->imgCache->GetMediaLink($cid.$mode).'" class="media" ';
149        $tag .= 'alt="PubChem image '.$cid.'" ';
150        $tag .= 'title="CID:'.$cid.'  Click to PubChem page"/></a></div>';
151        return $tag;
152  }
153
154 /**
155  * Get properties from XML data
156  * @param string $cid
157  * @return boolean
158  */
159  function getProperties($cid){
160    $xml = $this->getPubchemXml($cid);
161    if ($xml===false){
162      return false;
163    }
164    $x = new Xml;
165    $XmlClass = $x->GetXmlObject($xml);
166    $xmls = $XmlClass[0]->next[0]->next;
167    $ext_props = array();
168    for($i=0;$i<count($xmls);$i++){
169      if ($xmls[$i]->tag=="PC-Compound_props"){
170        $props = $xmls[$i]->next;
171        for($j=0;$j<count($props);$j++){
172          $infodata = $props[$j]->next;
173
174          $info_name1 = $infodata[0]->next[0]->next[0]->value;
175          $info_name2 = $infodata[0]->next[0]->next[1]->value;
176          $info_value = $infodata[1]->next[0]->value;
177
178          switch($info_name1){
179            case "Molecular Formula":
180              $ext_props['formula'] = $this->getChemFormat($info_value);
181              break;
182            case "IUPAC Name":
183              if ($info_name2=="Preferred"||$info_name2=="Allowed"){
184                if(strlen($info_value)>50){ $info_value = str_replace("-","- ",$info_value);}
185                $ext_props['iupac'] = $info_value;
186              }
187              break;
188            case "Molecular Weight":
189              $ext_props['mw'] = $info_value;
190              break;
191            case "Log P":
192              $ext_props['xlogp'] = $info_value;
193              break;
194            case "SMILES":
195              $ext_props['smiles'] = $info_value;
196              break;
197          }
198        }
199      }
200    }
201    // save extracted properties
202    $this->propCache->PutMediaText($cid,json_encode($ext_props));
203    return $ext_props;
204  }
205 /**
206  * Get PubChem XML
207  */
208  function getPubchemXml($cid){
209    global $conf;
210    $xml = $this->ncbi->GetPubchemXml($cid);
211    if (!empty($xml)){
212      $filepath = $this->xmlCache->GetMediaPath($cid);
213      if(io_saveFile($filepath,$xml)){
214        chmod($filepath,$conf['fmode']);
215      }
216      return $xml;
217    }else{
218      return false;
219    }
220  }
221 /**
222  * Get chemical format.
223  */
224  function getChemFormat($raw){
225    $pattern = array("/[\|]?([0-9]*\+|[0-9]*\-)/","/([A-Z]|[A-Z][a-z]|\)|\])([0-9]+)/");
226    $replace = array("<sup>\${1}</sup>","\${1}<sub>\${2}</sub>");
227    return preg_replace($pattern,$replace,$raw);
228  }
229  /**
230   * table name row for a template
231   * @param Doku_Renderer $renderer
232   * @param string $cid
233   * @param string $iupac
234   * @param string $title
235   */
236  function _name_row(&$renderer,$cid,$iupac='',$title=''){
237      $renderer->tablerow_open();
238      $renderer->tableheader_open();
239      $renderer->doc.=($title!='')?$this->getLang('mol_name'):'CID';
240      $renderer->tableheader_close();
241      $renderer->tablecell_open();
242      $renderer->doc.=($title!='')?$title:$cid;
243      if($iupac){
244          $renderer->footnote_open();
245          $renderer->doc.=$iupac;
246          $renderer->footnote_close();
247      }
248      $renderer->tablecell_close();
249      $renderer->tablerow_close();
250  }
251
252  /**
253   * Render table row for a template
254   * @param Doku_Renderer $renderer
255   * @param string $head
256   * @param string $cell
257   */
258  function _row(&$renderer,$head,$cell){
259      if(empty($cell))return;
260      $renderer->tablerow_open();
261      $renderer->tableheader_open();
262      $renderer->doc.=$head;
263      $renderer->tableheader_close();
264      $renderer->tablecell_open();
265      $renderer->doc.=$cell;
266      $renderer->tablecell_close();
267      $renderer->tablerow_close();
268  }
269}
270?>
271