from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from ost import *
from ost import gui
from ost.gui.init_splash import _InitSplash
from ost.gui.dng import termuse
from ost.gui.dng import superpositiondialog

import sys
class FileMenu(QMenu):
  def __init__(self, parent=None):
    QMenu.__init__(self, parent)
    self.setTitle('File')
    gui.AddMenuAction(self, 'Open', self._Open, shortcut='Ctrl+O')
    gui.AddMenuAction(self, 'Save As...', self._SaveAs, 
                  shortcut='Ctrl+Shift+S', 
                  enabled=gui.OneOf(gfx.Entity))
  def _Open(self):
    filename,_=QFileDialog.getOpenFileName(None, 'Open file','')
    if(QFileInfo(filename).isFile()):
      gui.FileLoader.LoadObject(str(filename))

  def _SaveAs(self):
    sel_node=gui.SceneSelection.Instance().GetActiveNode(0)
    filename=QFileDialog.getSaveFileName(None, 'Save As', 
                                         '%s.pdb' % sel_node.name)
    io.SavePDB(sel_node.view, str(filename))
    
class ClipWidget(QWidget):
  def __init__(self, width=500, height=500):
    QWidget.__init__(self)
    self.setWindowFlags(Qt.Tool)
    l = QGridLayout(self)
    l.addWidget(QLabel("Near"), 0, 0)
    l.addWidget(QLabel("Far"), 1, 0)
    bounds_near = QLineEdit(str(0))
    bounds_near.setValidator(QIntValidator(0, 9999, bounds_near))
    bounds_near.setMaxLength(4)
    bounds_near.setMaximumWidth(50)
    bounds_far = QLineEdit(str(200))
    bounds_far.setValidator(QIntValidator(0, 9999, bounds_far))
    bounds_far.setMaxLength(4)
    bounds_far.setMaximumWidth(50)
    l.addWidget(bounds_near, 0, 1, 2, 1)
    l.addWidget(bounds_far, 0, 3, 2, 1)
    self.near_ = QSlider(Qt.Horizontal)
    self.near_.setMinimum(int(bounds_near.text()))
    self.near_.setMaximum(int(bounds_far.text()))
    self.near_.setValue(int(gfx.Scene().near))
    self.far_ = QSlider(Qt.Horizontal)
    self.far_.setMinimum(int(bounds_near.text()))
    self.far_.setMaximum(int(bounds_far.text()))
    far = int(gfx.Scene().far)
    if far>sys.maxsize:
      far = sys.maxsize
    self.far_.setValue(far)
    self.auto_ = QCheckBox("Continuous Automatic Clipping")
    self.auto_.setChecked(gfx.Scene().GetAutoAutoslab())

    l.addWidget(self.near_, 0, 2)
    l.addWidget(self.far_, 1, 2)
    l.addWidget(self.auto_, 2, 0, 1, 4)
    self.near_.valueChanged.connect(self.SetNear)
    self.far_.valueChanged.connect(self.SetFar)
    self.auto_.stateChanged.connect(self.SetAuto)
    bounds_near.textEdited.connect(self.SetNearBounds)
    bounds_far.textEdited.connect(self.SetFarBounds)

  def SetNear(self, val):
    gfx.Scene().near = val

  def SetFar(self, val):
    gfx.Scene().far = val

  def SetAuto(self, val):
    gfx.Scene().AutoAutoslab(val)
    gfx.Scene().near = int(self.near_.value())
    gfx.Scene().far = int(self.far_.value())

  def SetNearBounds(self, text):
    if text!='':
      self.near_.setMinimum(int(text))
      self.far_.setMinimum(int(text))

  def SetFarBounds(self, text):
    if text!='':
      self.near_.setMaximum(int(text))
      self.far_.setMaximum(int(text))

class ExportSceneDialog(QDialog):
  def __init__(self, width=500, height=500):
    QDialog.__init__(self)
    l=QGridLayout(self)
    l.setColumnMinimumWidth(0, 100)
    l.addWidget(QLabel("Width (px)"), 0, 0)
    l.addWidget(QLabel("Height (px)"), 1, 0)
    self.width_=QLineEdit(str(width))
    self.height_=QLineEdit((str(height)))
    self.width_.setValidator(QIntValidator(50, 3000, self.width_))
    self.height_.setValidator(QIntValidator(50, 3000, self.height_))
    self.opaque_=QCheckBox("Force Opaque Background")
    l.addWidget(self.width_, 0, 1)
    l.addWidget(self.height_, 1, 1)
    l.addWidget(self.opaque_, 2, 1)
    hbox=QHBoxLayout()
    cancel=QPushButton("Cancel")
    cancel.clicked.connect(self.reject)
    hbox.addWidget(cancel)
    export=QPushButton("Export")
    hbox.addWidget(export)
    export.setDefault(True)
    l.addLayout(hbox, 3, 1, 2, 1)
    export.clicked.connect(self.accept)
  @property
  def transparent(self):
    return not self.opaque_.isChecked()

  @property
  def width(self):
    return int(self.width_.text())

  @property
  def height(self):
    return int(self.height_.text())

class SceneMenu(QMenu):
  def __init__(self, parent=None):
    QMenu.__init__(self, parent)
    self.setTitle('Scene')
    self.aboutToShow.connect(self._AboutToShow)
    gui.AddMenuAction(self, 'Background Color', self._SetSceneBackground)
    self.fog_action=gui.AddMenuAction(self, 'Depth Cueing', self._ToggleFog, 
                                  shortcut='Ctrl+Shift+F', checkable=True, 
                                  checked=gfx.Scene().fog)
    gui.AddMenuAction(self, 'Center', self._Center,
                  enabled=gui.ManyOf(gfx.GfxObj))
    gui.AddMenuAction(self, 'Fit To Screen', self._FitToScreen,
                  enabled=gui.OneOf(gfx.Entity))
    gui.AddMenuAction(self, 'Superpose', self._SuperposeDialog,
                      enabled=gui.TwoOf(gfx.Entity))
    gui.AddMenuAction(self, 'Save Snapshot', self._ExportScene)
    gui.AddMenuAction(self, 'Scene Clipping', self._ClipScene, shortcut='Ctrl+Shift+C')
    
  def _ExportScene(self):
    qd=ExportSceneDialog()
    if not qd.exec_():
      return

    options = QFileDialog.Options()
    options |= QFileDialog.DontUseNativeDialog
    filename, _ = QFileDialog.getSaveFileName(self,"Save Snapshot","snapshot.png", "", options=options)

    if filename:
      gfx.Scene().Export(str(filename), qd.width, qd.height, qd.transparent)

  def _ClipScene(self):
    self.cw = ClipWidget()
    self.cw.show()

  def _AboutToShow(self):
    self.fog_action.setChecked(gfx.Scene().fog)
    
  def _Center(self):
    sel=gui.SceneSelection.Instance()
    gfx.Scene().center=sel.GetActiveNode(0).center

  def _SetSceneBackground(self):
    new_color=gui.PickColor(gfx.Scene().bg)
    if new_color:
      gfx.Scene().bg=new_color

  def _ToggleFog(self):
    gfx.Scene().fog=not gfx.Scene().fog
    self.fog_action.setChecked(gfx.Scene().fog)

  def _FitToScreen(self):
    sel=gui.SceneSelection.Instance()
    gfx.FitToScreen(sel.GetActiveNode(0))

  def _SuperposeDialog(self):
    sel=gui.SceneSelection.Instance()
    act_count=sel.GetActiveNodeCount()
    # we now that there have to be 2 gfx.Entities, because of using TwoOf to
    # enable menu entry!
    i = 0;
    gfx_ent_1 = sel.GetActiveNode(i)
    while not isinstance(gfx_ent_1, gfx.Entity):
      i += 1
      gfx_ent_1 = sel.GetActiveNode(i)
    i += 1
    gfx_ent_2 = sel.GetActiveNode(i)
    while not isinstance(gfx_ent_2, gfx.Entity):
      i += 1
      gfx_ent_2 = sel.GetActiveNode(i)
    sd = superpositiondialog.SuperpositionDialog(gfx_ent_1, gfx_ent_2)
    if sd.rmsd_superposed_atoms != None:
      if sd.reference == 0:
        gfx_ent_2.UpdatePositions()
        gfx.Scene().CenterOn(gfx_ent_1)
      else:
        gfx_ent_1.UpdatePositions()
        gfx.Scene().CenterOn(gfx_ent_2)
      LogScript('RMSD: %.3f'%sd.rmsd)  
      LogScript('RMSD superposed atoms: %.3f'%sd.rmsd_superposed_atoms) 
      LogScript('fraction superposed: %.3f'%sd.fraction_superposed)   
    elif sd.rmsd != None:
      if sd.reference == 0:
        gfx_ent_2.UpdatePositions()
        gfx.Scene().CenterOn(gfx_ent_1)
      else:
        gfx_ent_1.UpdatePositions()
        gfx.Scene().CenterOn(gfx_ent_2)
      LogScript('RMSD: %.3f'%sd.rmsd)
    elif sd.superposition_error != None:
      LogScript('Superposition Failed: ' + sd.superposition_error)
    else:
      LogScript('Superposition Failed!')

class WindowMenu(QMenu):
  def __init__(self, parent=None):
    QMenu.__init__(self, parent)
    self.setTitle('Window')
    gosty=gui.GostyApp.Instance()
    self.aboutToShow.connect(self._AboutToShow)
    inspector_visible=gosty.GetWidget('InspectorDialog').isVisible()
    self._gl_win_action=gui.AddMenuAction(self, 'GL Window',  
                                      self._ToggleShowGLWindow, checkable=True,
                                      checked=gosty.gl_win.qobject.isVisible(),
                                      shortcut='Ctrl+G')
    self._inspector_action=gui.AddMenuAction(self, 'Inspector', 
                                         self._ToggleShowInspector,
                                         checkable=True,
                                         checked=inspector_visible,
                                         shortcut='Ctrl+I')
    self.addSeparator()
    self.addMenu(gosty.perspective.panels.menu)
    gui.AddMenuAction(self, 'Reset View', self._ResetView)
  def _AboutToShow(self):
    gosty=gui.GostyApp.Instance()
    self._gl_win_action.setChecked(gosty.gl_win.qobject.isVisible())
    inspector_visible=gosty.GetWidget('InspectorDialog').isVisible()
    self._inspector_action.setChecked(inspector_visible)
    
  def _ToggleShowGLWindow(self):
    gosty=gui.GostyApp.Instance()
    gl_win=gosty.GetGLWin()
    if gl_win and gl_win.qobject.isHidden():
      gl_win.Show()
    else:
      gl_win.Hide()

  def _ToggleShowInspector(self):
    gosty=gui.GostyApp.Instance()
    inspector=gosty.GetWidget('InspectorDialog')
    if inspector and inspector.isHidden():
      inspector.show()
    else:
      inspector.hide()
      
  def _ResetView(self):
    msg_box = QMessageBox()
    msg_box.setWindowTitle("Reset the Panels and Widget");
    msg_box.setIcon(QMessageBox.Question)
    msg_box.setText("Do you really want to reset the Panels and Widgets?");
    msg_box.setStandardButtons(QMessageBox.Yes |
                               QMessageBox.Cancel);
    msg_box.setDefaultButton(QMessageBox.Cancel);
    ret = msg_box.exec_();
    if(ret == QMessageBox.Yes):
      settings = QSettings()
      settings.setValue("restore_settings",QVariant(False))
      info_box = QMessageBox()
      info_box.setStandardButtons(QMessageBox.Ok)
      info_box.setIcon(QMessageBox.Information)
      info_box.setWindowTitle("Restart OpenStructure")
      info_box.setText("You must restart OpenStructure for the changes to take effect!");
      info_box.exec_();

class HelpMenu(QMenu):
  def __init__(self, parent=None):
    QMenu.__init__(self, parent)
    self.setTitle('Help')
    gui.AddMenuAction(self, 'Documentation', self._VisitDocs)
    gui.AddMenuAction(self, 'About', self._ShowAboutDialog)
    if sys.platform=='darwin':
      gui.AddMenuAction(self, 'Install Command Line Tool',
                    termuse.InstallTerminalPrograms)
  def _VisitDocs(self):
    QDesktopServices.openUrl(QUrl("http://www.openstructure.org/docs/"))
  
  def _ShowAboutDialog(self):
    _InitSplash()

def _InitMenu():
  _InitMenu.mbar=gui.GostyApp.Instance().perspective.GetMenuBar()
  file_menu=FileMenu(_InitMenu.mbar)
  scene_menu=SceneMenu(_InitMenu.mbar)
  win_menu=WindowMenu(_InitMenu.mbar)
  help_menu=HelpMenu(_InitMenu.mbar)
  _InitMenu.mbar.addMenu(file_menu)
  _InitMenu.mbar.addMenu(scene_menu)
  _InitMenu.mbar.addMenu(win_menu)
  _InitMenu.mbar.addMenu(help_menu)