content: /**
   * Copyright (C) 2010 EdgyTech LLC.
   *
   * Licensed under the Apache License, Version 2.0 (the "License"); you may not
   * use this file except in compliance with the License. You may obtain a copy of
   * the License at
   *
   * http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
   * License for the specific language governing permissions and limitations under
   * the License.
   */
  package com.edgytech.umongo;
  
  import com.edgytech.swingfast.*;
  import java.awt.Component;
  import java.awt.Rectangle;
  import java.util.concurrent.ExecutionException;
  import java.util.logging.Level;
  import javax.swing.SwingUtilities;
  
  /**
   *
   * @author antoine
   */
  public class TextView extends Zone implements EnumListener, TabInterface, Runnable {
  
      enum Item {
  
          textArea,
          tabDiv,
          tabTitle,
          tabClose,
          refresh,
          export,
          tools,
          startAutoUpdate,
          stopAutoUpdate
      }
  
      TabbedDiv tabbedDiv;
      Thread updateThread;
      int updateInterval;
      int updateCount;
      boolean running;
      DbJob job;
  
      public TextView(String id, String label, DbJob job) {
          try {
              xmlLoad(Resource.getXmlDir(), Resource.File.textView, null);
          } catch (Exception ex) {
              getLogger().log(Level.SEVERE, null, ex);
          }
          setEnumBinding(Item.values(), this);
  
          setId(id);
          setLabel(label);
          this.job = job;
          setStringFieldValue(Item.tabTitle, label);
  
          ((MenuItem) getBoundUnit(Item.refresh)).enabled = true;
          ((MenuItem) getBoundUnit(Item.startAutoUpdate)).enabled = true;
      }
  
      /**
       * create a doc view with static document
       *
       * @param id
       * @param label
       * @param job
       * @param root
       * @param doc
       */
      public TextView(String id, String label, DbJob job, String text) {
          this(id, label, job);
  
          if (text != null) {
              setContent(text);
          }
      }
  
      public void close(ButtonBase button) {
          tabbedDiv.removeTab(this);
      }
  
      void addToTabbedDiv() {
          tabbedDiv = UMongo.instance.getTabbedResult();
          tabbedDiv.addTab(this, true);
      }
  
      public void actionPerformed(Enum enm, XmlComponentUnit unit, Object src) {
      }
  
  //    public void export(ButtonBase button) throws IOException {
  //        // export should be run in thread, to prevent concurrent mods
  //        ExportDialog dia = UMongo.instance.getGlobalStore().getExportDialog();
  //        if (!dia.show()) {
  //            return;
  //        }
  //        final DocumentSerializer ds = dia.getDocumentSerializer();
  //        try {
  //            DefaultMutableTreeNode root = getTree().getTreeNode();
  //            for (int i = 0; i < root.getChildCount(); ++i) {
  //                DefaultMutableTreeNode child = (DefaultMutableTreeNode) root.getChildAt(i);
  //                Object obj = child.getUserObject();
  //                DBObject doc = null;
  //                if (obj instanceof DBObject) {
  //                    doc = (DBObject) obj;
  //                } else if (obj instanceof TreeNodeDocumentField) {
  //                    doc = (DBObject) ((TreeNodeDocumentField) obj).getValue();
  //                } else if (obj instanceof TreeNodeDocument) {
  //                    doc = ((TreeNodeDocument) obj).getDBObject();
  //                }
  //                if (doc != null) {
  //                    ds.writeObject(doc);
  //                }
  //            }
  //        } finally {
  //            ds.close();
  //        }
  //    }
  
      public Component getTabComponent() {
          return getComponentBoundUnit("tabDiv").getComponent();
      }
  
      TextArea getTextArea() {
          return (TextArea) getBoundUnit(Item.textArea);
      }
      
      public void startAutoUpdate(ButtonBase button) {
          AutoUpdateDialog dia = UMongo.instance.getGlobalStore().getAutoUpdateDialog();
          if (!dia.show()) {
              return;
          }
  
          if (updateThread != null) {
              stopAutoUpdate(null);
          }
  
          updateThread = new Thread(this);
          updateInterval = dia.getComponentIntFieldValue(AutoUpdateDialog.Item.autoInterval);
          updateCount = dia.getComponentIntFieldValue(AutoUpdateDialog.Item.autoCount);
          running = true;
          updateThread.start();
  
          getComponentBoundUnit(Item.stopAutoUpdate).enabled = true;
          getComponentBoundUnit(Item.stopAutoUpdate).updateComponent();
      }
  
      public void stopAutoUpdate(ButtonBase button) {
          running = false;
          try {
              updateThread.interrupt();
              updateThread.join();
          } catch (InterruptedException ex) {
          }
          updateThread = null;
  
          getComponentBoundUnit(Item.stopAutoUpdate).enabled = false;
          getComponentBoundUnit(Item.stopAutoUpdate).updateComponent();
      }
  
      public void run() {
          int i = 0;
          while (running) {
              try {
                  DbJob job = getRefreshJob();
                  final DbJob fjob = job;
  
                  SwingUtilities.invokeAndWait(new Runnable() {
  
                      @Override
                      public void run() {
                          fjob.addJob();
                      }
                  });
  
                  try {
                      fjob.join();
                  } catch (InterruptedException ex) {
                      getLogger().log(Level.WARNING, null, ex);
                  } catch (ExecutionException ex) {
                      getLogger().log(Level.WARNING, null, ex);
                  }
  
                  if (updateCount > 0 && ++i >= updateCount) {
                      break;
                  }
                  
                  Thread.sleep(updateInterval * 1000);
  
              } catch (Exception ex) {
                  getLogger().log(Level.SEVERE, null, ex);
              }
          }
          getLogger().log(Level.INFO, "Ran " + i + " updates");
      }
  
      public void refresh(ButtonBase button) {
          getRefreshJob().addJob();
      }
          
      public DbJob getRefreshJob() {
          if (job == null) {
              return null;
          }
  
          DbJob newJob = new DbJob() {
  
              String result;
  
              @Override
              public Object doRun() throws Exception {
                  result = (String) job.doRun();
                  return null;
              }
  
              @Override
              public String getNS() {
                  return job.getNS();
              }
  
              @Override
              public String getShortName() {
                  return job.getShortName();
              }
  
              @Override
              public void wrapUp(Object res) {
                  super.wrapUp(res);
                  if (res == null && result != null) {
  //                    setContent(result);
  //                    getTextArea().updateComponent();
                      appendContent(result);
                      
                      // panel info may need to be refreshed
                      if (job.getPanel() != null) {
                          job.getPanel().refresh();
                      }
                  }
              }
          };
          
          return newJob;
      }
  
      public void setContent(String text) {
          setStringFieldValue(Item.textArea, text);
      }
      
      /**
       * Following method doesnt really work because the log buffer is a short moving window
       */
      public void swapContent(String text) {
          TextArea ta = (TextArea) getBoundUnit(Item.textArea);
  //        int pos = ta.getTextArea().getCaretPosition();
          int val = ta.getComponent().getVerticalScrollBar().getValue();
          int max = ta.getComponent().getVerticalScrollBar().getMaximum();
          int vis = ta.getComponent().getVerticalScrollBar().getVisibleAmount();
          
          setStringFieldValue(Item.textArea, text);
          updateComponent();
  
          // scroll resets, set it back if not to close to the end
  //        System.out.println(val + " " + max + " " + vis);
          if (val < max - vis)
              ta.getComponent().getVerticalScrollBar().setValue(val);
      }
      
      public void appendContent(String text) {
          final TextArea ta = (TextArea) getBoundUnit(Item.textArea);
          // since logs are moving window, need to find the spot within new log
          String old = ta.getComponentStringValue();
          int last = old.lastIndexOf("\n", old.length() - 5);
          String lastLine = old.substring(last + 1);
          int pos = text.indexOf(lastLine);
          if (pos >= 0)
              text = text.substring(pos + lastLine.length());
  
          final int val = ta.getComponent().getVerticalScrollBar().getValue();
          int max = ta.getComponent().getVerticalScrollBar().getMaximum();
          int vis = ta.getComponent().getVerticalScrollBar().getVisibleAmount();
          Rectangle rect = ta.getComponent().getVisibleRect();
              
          ta.getTextArea().append(text);
  
          // scroll resets, set it back if not to close to the end, needs to be done at later time in EVT
          if (val < max - 2 * vis) {
              SwingUtilities.invokeLater(new Runnable() {
  
                  @Override
                  public void run() {
                      ta.getComponent().getVerticalScrollBar().setValue(val);
                  }
              });
  
          }
          
      }
  
  }
  