# Copyright 2004,2005 Pierre Martineau <pmartino@users.sourceforge.net>
# This file is part of Bibus, a bibliographic database that can
# work together with OpenOffice.org to generate bibliographic indexes.
#
# Bibus is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# Bibus is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Bibus; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA.
#
# generated by wxGlade 0.2 on Wed May 28 22:47:35 2003
# Then edited by hand
# DO NOT EDIT WITH wxGLADE'

import wx
import urllib, xml.dom.minidom, Import.PubMedXML, BIB

tool = 'bibus'						# used to identify the software at ncbi in case of problem
email= 'pmartino@users.sourceforge.net' # used to identify the software at ncbi in case of problem
#pubmed = BIB.PUBMED = "http://eutils.ncbi.nlm.nih.gov/entrez/eutils"
#pubmed = "http://www.ncbi.nlm.nih.gov.gate2.inist.fr/sites/entrez/eutils"	# biblioinserm
#proxies = {'http': 'http://www.someproxy.com:3128'}
#filehandle = urllib.urlopen(some_url, proxies=proxies)
# We use BIB.PROXIES

class SearchMedline(wx.Dialog):
	def __init__(self,db, *args, **kwds):
		kwds["style"] = wx.DEFAULT_FRAME_STYLE | wx.TAB_TRAVERSAL
		wx.Dialog.__init__(self, *args, **kwds)
		self.SearchList = [u'All Fields [ALL]', u'Text Words [TW]', u'Author [AU]', u'Title [TI]', u'Journal Title [TA]', u'Publication Date [DP]', u'Publication Type [PT]', u'Entrez Date [EDAT]', u'Pagination [PG]', u'Volume [VI]', u'Issue [IP]', u'Unique Identifiers [UID]', u'Personal Name as Subject [PS]', u'MeSH Terms [MH]', u'MeSH Date [MHDA]', u'MeSH Major Topic [MAJR]', u'MeSH Subheadings [SH]', u'Affiliation [AD]', u'EC/RN Number [RN]', u'Filter [FILTER]', u'Language [LA]', u'Secondary Source ID [SI] ', u'Subset [SB]', u'Substance Name [NM]']
		self.KeyList = ('[ALL]', '[TW]', '[AU]', '[TI]', '[TA]', '[DP]', '[PT]', '[EDAT]', '[PG]', '[VI]', '[IP]', '[UID]', '[PS]', '[MH]', '[MHDA]', '[MAJR]', '[SH]', '[AD]', '[RN]', '[FILTER]', '[LA]', '[SI]]', '[SB]', '[N]')
		self.SearchBool = ['AND','OR','NOT']
		self.db=db
		self.parent = args[0]
		# Top of the Dialog
		self.Mode = wx.RadioBox(self, -1, _("Mode"), choices=[_('Normal'), _('Expert')], majorDimension=0, style=wx.RA_SPECIFY_COLS)
		self.label_NumbRec= wx.StaticText(self, -1, _("Number of records"))
		self.NumbRec = wx.SpinCtrl(self, -1, min=1, max=10000)
		self.NumbRec.SetValue(BIB.PUBMED_NB)
		self.label_FirstRec = wx.StaticText(self, -1, _("Start at record"))
		self.FirstRec = wx.SpinCtrl(self, -1, "0", min=0, max=10000)
		self.static_line_1 = wx.StaticLine(self, -1)
		#
		# TextCtrl to enter query in expert mode
		self.ExpertValue = wx.TextCtrl(self, -1, u"", style=wx.TE_MULTILINE)
		# wx.Panel that enclose the grid
		self.PanelSearch = wx.Panel(self,-1)
		# Search grid
		self.ScrollWin = wx.ScrolledWindow(self.PanelSearch,style=wx.TAB_TRAVERSAL)	# in order to be able to scroll the choices grid
		self.ScrollWin.SetScrollRate(10,10)
		self.SearchBoolKey=[]
		self.SearchChoice=[]
		self.SearchValue=[]
		self.SearchBoolKey.append(wx.StaticText(self.ScrollWin, -1, u""))	# first line special since there is no bool choice
		self.SearchChoice.append(wx.Choice(self.ScrollWin, -1, choices=self.SearchList))
		self.SearchValue.append(wx.TextCtrl(self.ScrollWin, -1, u""))
		for line in range(1,4):
			self.SearchBoolKey.append(wx.Choice(self.ScrollWin, -1, choices=self.SearchBool))
			self.SearchChoice.append(wx.Choice(self.ScrollWin, -1, choices=self.SearchList))
			self.SearchValue.append(wx.TextCtrl(self.ScrollWin, -1, u""))
		# Button to add line
		self.static_line_2 = wx.StaticLine(self.PanelSearch, -1)
		self.button_Add = wx.Button(self.PanelSearch, -1, _("Add a line"))
		self.static_line_3 = wx.StaticLine(self, -1)
		#
		self.button_Cancel = wx.Button(self, wx.ID_CANCEL, _("Cancel"))
		self.button_Search = wx.Button(self, wx.ID_OK, _("Search"))
		self.button_SearchClose = wx.Button(self, -1, _("Search && Close"))
		self.button_Count = wx.Button(self, -1, _("Count"))

		self.__set_properties()
		self.__do_layout()
		self.__set_event()
		self.SetDimensions(BIB.PUBMED_X, BIB.PUBMED_Y, BIB.PUBMED_WIDTH, BIB.PUBMED_HEIGHT)
		#self.CenterOnParent()

	def __set_properties(self):
		self.SetTitle(_("Medline Search"))
		self.Mode.SetSelection(0)
		self.SearchChoice[0].SetSelection(0)
		for line in range(1,4):
			self.SearchChoice[line].SetSelection(0)
			self.SearchBoolKey[line].SetSelection(0)
		self.button_Search.SetDefault()
		self.SearchValue[0].SetFocus()	# we give focus to the first entry box

	def __do_layout(self):
		sizer_1 = wx.BoxSizer(wx.VERTICAL)	# top sizer if the dialog window
		sizer_2 = wx.BoxSizer(wx.HORIZONTAL)	# for top of the dialog
		self.grid_sizer_1 = wx.FlexGridSizer(0, 3, vgap=0, hgap=0)	# main grid
		self.sizer = wx.BoxSizer(wx.VERTICAL) # sizer enclosing scrolled window + button 'Add line' = sizer of self.PanelSearch
		sizer_3 = wx.BoxSizer(wx.HORIZONTAL)	# for buttons (bottom)
		grid_sizer_2 = wx.GridSizer(2, 2, vgap=5, hgap=5)	# for spinButtons (number of record)
		#
		# Set top of the dialog
		# number of record
		grid_sizer_2.Add(self.label_NumbRec, 0, wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL,0)
		grid_sizer_2.Add(self.NumbRec,0,0,0)
		grid_sizer_2.Add(self.label_FirstRec, 0, wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL,0)
		grid_sizer_2.Add(self.FirstRec,0,0,0)
		sizer_2.Add(self.Mode,0,wx.ALIGN_RIGHT|wx.ALL,5)
		sizer_2.Add((10,0),1,0,0)
		sizer_2.Add(grid_sizer_2,0,wx.ALIGN_RIGHT,0)
		sizer_1.Add(sizer_2,0,wx.EXPAND,0)
		sizer_1.Add(self.static_line_1,0,wx.EXPAND,0)
		#
		# Set grid
		for line in range(4):
			self.grid_sizer_1.Add(self.SearchBoolKey[line],0,0,0)
			self.grid_sizer_1.Add(self.SearchChoice[line],0,0,0)
			self.grid_sizer_1.Add(self.SearchValue[line],0,wx.EXPAND,0)
		self.grid_sizer_1.AddGrowableCol(2)
		self.ScrollWin.SetSizer(self.grid_sizer_1)
		self.grid_sizer_1.Fit(self.ScrollWin)
		#self.grid_sizer_1.SetSizeHints(self.ScrollWin)
		self.ScrollWin.Layout()
		self.sizer.Add(self.ScrollWin,1,wx.EXPAND,0)
		# Add line button
		self.sizer.Add(self.static_line_2,0,wx.EXPAND,0)
		self.sizer.Add(self.button_Add,0,wx.EXPAND,0)
		self.PanelSearch.SetSizerAndFit(self.sizer)
		#
		sizer_1.Add(self.PanelSearch,1,wx.EXPAND,0)
		# when expert selected
		sizer_1.Add(self.ExpertValue,1,wx.EXPAND,0)
		sizer_1.Show(self.ExpertValue,False)	# Masked at startup
		#
		sizer_1.Add(self.static_line_3,0,wx.EXPAND,0)
		#
		# Set Bottom Buttons
		sizer_3.Add(self.button_Cancel, 0, wx.ALL,5)
		sizer_3.Add(self.button_Search, 0, wx.ALL,5)
		sizer_3.Add(self.button_SearchClose, 0, wx.ALL,5)
		sizer_3.Add(self.button_Count, 0, wx.ALL,5)
		sizer_1.Add(sizer_3,0,wx.ALIGN_CENTER_HORIZONTAL,0)
		#
		self.SetAutoLayout(1)
		self.SetSizer(sizer_1)
		sizer_1.Fit(self)
		sizer_1.SetSizeHints(self)
		self.Layout()

	def __set_event(self):
		wx.EVT_BUTTON(self,wx.ID_OK,self.onSearch)
		wx.EVT_BUTTON(self,wx.ID_CANCEL,self.onCloseWindow)
		wx.EVT_CLOSE(self, self.onCloseWindow)
		wx.EVT_BUTTON(self,self.button_Add.GetId(),self.addLine)
		wx.EVT_BUTTON(self,self.button_SearchClose.GetId(),self.onSearchClose)
		wx.EVT_BUTTON(self,self.button_Count.GetId(),self.onCount)
		wx.EVT_RADIOBOX(self,self.Mode.GetId(),self.onMode)

	def onMode(self,event):
		selection = self.Mode.GetStringSelection()
		if selection == _('Normal'):
			self.GetSizer().Show(self.ExpertValue,False)
			self.GetSizer().Show(self.PanelSearch,True)
		else:
			self.GetSizer().Show(self.PanelSearch,False)
			self.GetSizer().Show(self.ExpertValue,True)
			self.ExpertValue.SetValue(self.__makeSearch())	# set the expert value to the current Normal search
		self.Layout()

	def addLine(self,event):
		self.SearchBoolKey.append(wx.Choice(self.ScrollWin, -1, choices=self.SearchBool))
		self.SearchChoice.append(wx.Choice(self.ScrollWin, -1, choices=self.SearchList))
		self.SearchValue.append(wx.TextCtrl(self.ScrollWin, -1, u""))
		self.grid_sizer_1.Add(self.SearchBoolKey[-1],0,0,0)
		self.grid_sizer_1.Add(self.SearchChoice[-1],0,0,0)
		self.grid_sizer_1.Add(self.SearchValue[-1],0,wx.EXPAND,0)
		self.grid_sizer_1.Fit(self.ScrollWin)
		self.PanelSearch.Layout()
		self.Layout()

	def onCloseWindow(self,event):
		BIB.PUBMED_WIDTH, BIB.PUBMED_HEIGHT = self.GetSizeTuple()
		BIB.PUBMED_X, BIB.PUBMED_Y = self.GetPositionTuple()
		BIB.PUBMED_NB = self.NumbRec.GetValue()
		self.Destroy()

	def onSearchClose(self,event):
		self.onSearch(event)
		self.onCloseWindow(event)

	def __makeSearch(self):
		"""Return the search corresponding o the choices in Normal mode"""
		line = 0
		search = u''
		try:
			while self.SearchValue[line].GetValue() == u'': line = line +1
			search="""%s%s""" %(self.SearchValue[line].GetValue().strip(),self.KeyList[self.SearchChoice[line].GetSelection()])
			line = line +1
			while True:
				if self.SearchValue[line].GetValue():
					search = """%s %s %s%s""" %(search,self.SearchBoolKey[line].GetStringSelection(),self.SearchValue[line].GetValue().strip(),self.KeyList[self.SearchChoice[line].GetSelection()])
				line = line +1
		except IndexError: pass
		return search

	def __query_medline(self,rettype):
		if self.Mode.GetStringSelection() == _('Normal'):
			search = self.__makeSearch()
		else:
			search = self.ExpertValue.GetValue().strip()
		#
		retstart = self.FirstRec.GetValue()
		retmax = self.NumbRec.GetValue()
		#
		query = urllib.urlencode({'db':'pubmed','term':search,'retstart':retstart,'retmax':retmax,'usehistory':'y','rettype':rettype,'retmode':'xml','tool':tool,'email':email})
		#print query
		return urllib.urlopen("%s/esearch.fcgi"%BIB.PUBMED, query, proxies=BIB.PROXIES)

	def onSearch(self,event):
		f = self.__query_medline('uilist')
		try:
			mydom = xml.dom.minidom.parse(f)
			#print 'Count=',mydom.getElementsByTagName('Count')[0].firstChild.data
			#if (not mydom.getElementsByTagName('ERROR')) and (mydom.getElementsByTagName('Count')[0].firstChild.data != '0'):
			webenv = mydom.getElementsByTagName('WebEnv')[0].firstChild.data
			querykey = mydom.getElementsByTagName('QueryKey')[0].firstChild.data
			retstart = self.FirstRec.GetValue()
			retmax = self.NumbRec.GetValue()
			query = urllib.urlencode({'db':'pubmed','query_key':querykey,'retstart':retstart,'retmax':retmax,'retmode':'xml','rettype':'medline','tool':tool,'email':email})
			#print query	# ,'WebEnv':webenv
			# we don't want to quote WebEnv since it seems to cause problems (% for instance)
			f = urllib.urlopen("%s/efetch.fcgi"%BIB.PUBMED, "WebEnv=%s&%s" %(webenv,query), proxies=BIB.PROXIES)
			self.db.deleteOnline()	# clear last online search
			records = Import.PubMedXML.importRef(f)
			for CurRecord in records:
				#CurRecord = [u'NULL'] + CurRecord
				self.db.writeRefOnline(CurRecord)
			f.close()
			# update window list
			self.parent.keytree.SelectItem(self.parent.keytree.keyOnline)
			self.parent.updateList(self.db.getAllRefOnline(BIB.LIST_DISPLAY,BIB.LIST_ORDER,BIB.LIST_HOW,short=True))
		#else:
			#self.__showError()
		except:
			self.__showError()

	def onCount(self,event):
		f = self.__query_medline('count')
		try:
			mydom = xml.dom.minidom.parse(f)
			#if not mydom.getElementsByTagName('ERROR'):
			self.__showCount(mydom.getElementsByTagName('Count')[0].firstChild.data)
		except:
			self.__showError()

	def __showError(self):
		dlg=wx.MessageDialog(self, _("Error during query.\nIs your network connection working?\nIf required, you can set a proxy in the extended preferences."), caption = _("Error"), style = wx.OK | wx.CENTRE | wx.ICON_ERROR, pos = wx.DefaultPosition)
		try:
			dlg.ShowModal()
		finally:
			dlg.Destroy()

	def __showCount(self,count):
		dlg=wx.MessageDialog(self, _("There is %s such records in Medline")%count, caption = u"", style = wx.OK | wx.CENTRE | wx.ICON_INFORMATION, pos = wx.DefaultPosition)
		try:
			dlg.ShowModal()
		finally:
			dlg.Destroy()

# end of class Search_model


