/**
  * MainProgram constructor
  *
  * @param num - number of month
  * @param source - Directory to start search
  * @param hr - reference to HandlerView object that called to the constructor
  */
 public MainProgram(int num, File source, HandlerView hr) {
   _listOfFiles = new ArrayList<File>();
   _numOfMonth = num;
   _source = source;
   archiveDirectory = createArchive();
   /*TODO if added only for running UnitTest - should be without if*/
   if (hr != null) {
     list = hr.getList();
     progress = hr.getBar();
     handlerFrame = hr;
   } else {
     list = null;
     progress = null;
     handlerFrame = null;
   }
 }
  /**
   * Function that overrides SwingWorkers done() and displays the search results(files that were
   * found/ message about problems that occurred while search)
   */
  @SuppressWarnings({"rawtypes", "unchecked", "serial"})
  @Override
  protected void done() {
    progress.setIndeterminate(false);
    if (!isCancelled()) {
      try {
        if (!_listOfFiles.isEmpty()) {
          handlerFrame.enableButtons();
          list.setModel(
              new javax.swing.AbstractListModel() {
                String[] strings = get();

                public int getSize() {
                  return strings.length;
                }

                public Object getElementAt(int i) {
                  return strings[i];
                }
              });
          list.setEnabled(true);
        } else {
          list.setModel(
              new javax.swing.AbstractListModel() {
                String[] strings = {"No Files Were Found"};

                public int getSize() {
                  return 1;
                }

                public Object getElementAt(int i) {
                  return strings[i];
                }
              });
          JOptionPane.showMessageDialog(
              handlerFrame, "No Files Were Found", "DrCleaner", JOptionPane.INFORMATION_MESSAGE);
          handlerFrame.dispose();
        }
      } catch (InterruptedException ex) {
        JOptionPane.showMessageDialog(
            null, "Interupted while waiting for results", "Error", JOptionPane.ERROR_MESSAGE);
      } catch (ExecutionException ex) {
        JOptionPane.showMessageDialog(
            null, "Error encountered while performing search", "Error", JOptionPane.ERROR_MESSAGE);
      }
    } else handlerFrame.dispose();
  }
  /**
   * Function that overrides SwingWorkers doInBackground() and performs search for files that suits
   * user's criteria. The search performed in dedicated thread that runs in background.
   *
   * @return string[] that contains file names that were found in search
   */
  @Override
  @SuppressWarnings({"unchecked", "serial", "rawtypes"})
  protected String[] doInBackground() {
    handlerFrame.disableButtons();
    list.setModel(
        new javax.swing.AbstractListModel() {
          String[] strings = {"Searching..."};

          public int getSize() {
            return 1;
          }

          public Object getElementAt(int i) {
            return strings[i];
          }
        });
    if (isCancelled()) {
      list.setModel(
          new javax.swing.AbstractListModel() {
            String[] strings = {"Search operation was canceled"};

            public int getSize() {
              return 1;
            }

            public Object getElementAt(int i) {
              return strings[i];
            }
          });
      return fileList();
    } else {
      list.setEnabled(false);
      searchDirectory(_source);
      return fileList();
    }
  }
  /**
   * Function that implements archive algorithm. Function archives all the files that were found by
   * search and were selected by user to be archived. Function places an archive either in user's
   * DropBox account or saves it on users hard drive, according to users choice. At the end function
   * updates the list of files that displayed in Handler window.Function returns JList<String> of
   * remaining files.
   *
   * @param l - list of file with selected files to be compressed to archive.
   * @return updated list of files.
   */
  @SuppressWarnings({"rawtypes", "serial", "unchecked"})
  public JList<String> archiveFiles(JList<String> l) {
    list = l;
    if (list.getMaxSelectionIndex() == -1)
      JOptionPane.showMessageDialog(
          null,
          "Please select files to be archived! ",
          "DrCleaner",
          JOptionPane.INFORMATION_MESSAGE);
    else {
      int j =
          JOptionPane.showConfirmDialog(
              null,
              "Are you sure you want to archive selected fles? ",
              "DrCleaner",
              JOptionPane.YES_NO_OPTION);
      if (j == JOptionPane.YES_OPTION) {
        String[] choises = {"Desktop Archive", "Dropbox archive", "Cancel"};
        int responce =
            JOptionPane.showOptionDialog(
                handlerFrame,
                "Please choose where to place your archive",
                "Archive",
                JOptionPane.YES_NO_OPTION,
                JOptionPane.PLAIN_MESSAGE,
                new ImageIcon(
                    HandlerView.class.getResource("/resources/document-archive-icon.png")),
                choises,
                "Desktop Archive");
        switch (responce) {
          case 0:
          case 1:
            {
              String archiveName = now();
              File newArchive =
                  new File(archiveDirectory.getAbsolutePath() + File.separatorChar + archiveName);
              newArchive.mkdir();
              final File zipFile = new File(newArchive.getAbsolutePath() + ".zip");
              long space = 0;
              int numOfFilesThatCouldntArchive = 0;
              int numOfselected = 0;
              final Vector<String> temp = new Vector<String>();
              Vector<File> archiveListOfFileNames =
                  new Vector<File>(); // Will contain files that are placed in archive
              for (int i = 0; i < list.getModel().getSize(); i++) {
                if (list.isSelectedIndex(i)) {
                  numOfselected++;

                  /*
                   * Because in the archive files stored only by their names(not the full path). we need to check if there are
                   * files that have same names and rename them by adding "(index)" at the end of the name and just before the extension
                   **/
                  File from = new File((String) list.getModel().getElementAt(i));
                  int extensionStartsAt = from.getName().lastIndexOf('.');
                  String newName = from.getName().substring(0, extensionStartsAt);
                  String extension =
                      from.getName().substring(extensionStartsAt, from.getName().length());
                  int counterOfFilesWithSameName = 2;
                  String newName2 = new String(newName);
                  File to =
                      new File(newArchive.getAbsolutePath() + File.separatorChar + from.getName());
                  for (int k = 0; k < archiveListOfFileNames.size(); k++) {
                    if (archiveListOfFileNames.get(k).getName().equals(to.getName())) {
                      newName2 = newName + "(" + counterOfFilesWithSameName + ")";
                      to =
                          new File(
                              newArchive.getAbsolutePath()
                                  + File.separatorChar
                                  + newName2
                                  + extension);
                      counterOfFilesWithSameName++;
                      k = -1;
                    }
                  }
                  try {
                    copyFile(from, to);
                    archiveListOfFileNames.add(to);
                    space += from.length();

                    // check that copy of file was made and that it is not corrupted.
                    if (to.exists() && from.length() == to.length()) from.delete();
                  } catch (IOException ex) {
                    ex.printStackTrace();
                  }
                } else temp.add((String) list.getModel().getElementAt(i));
              }
              try {
                // making archive file from all selected files
                zipDirectory(newArchive, zipFile);
                // checking that zip file is not corrupted
                if (isValid(zipFile)) {
                  for (File f : newArchive.listFiles()) f.delete();
                  newArchive.delete();
                }
                if (responce == 1) {
                  /*
                   * in case that user choose to place the archive in DropBox account - open transfer dialog.
                   * */
                  SwingUtilities.invokeLater(
                      new Runnable() {
                        @Override
                        public void run() {
                          TransferDialog t = new TransferDialog(zipFile);
                          t.setVisible(true);
                        }
                      });
                }
              } catch (IOException ex) {
                JOptionPane.showMessageDialog(
                    null,
                    "Problem occured while making archive ",
                    "DrCleaner",
                    JOptionPane.ERROR_MESSAGE);
                ex.printStackTrace();
              } catch (SecurityException ex) {
                JOptionPane.showMessageDialog(
                    null,
                    "Problem occured while deleting old files that were supposed to move to archive ",
                    "DrCleaner",
                    JOptionPane.ERROR_MESSAGE);
                ex.printStackTrace();
              }

              list.setModel(
                  new javax.swing.AbstractListModel() {
                    public int getSize() {
                      return temp.size();
                    }

                    public Object getElementAt(int i) {
                      return temp.get(i);
                    }
                  });
              list.repaint();
              if (responce == 0) {

                // Feedback that concludes archive operation
                long savedSpace = space - zipFile.length();
                String str =
                    "From "
                        + numOfselected
                        + " selected files, "
                        + (numOfselected - numOfFilesThatCouldntArchive)
                        + " were archived\n Total saved space is: "
                        + (savedSpace / 1024)
                        + "KB\n"
                        + "Your archive file is at: "
                        + newArchive.getAbsolutePath();
                JOptionPane.showMessageDialog(
                    null, str, "DrCleaner", JOptionPane.INFORMATION_MESSAGE);
              }
              if (temp.isEmpty()) {
                JOptionPane.showMessageDialog(
                    handlerFrame,
                    "You have no more files to handle",
                    "DrCleaner",
                    JOptionPane.INFORMATION_MESSAGE);
                handlerFrame.dispose();
              }
              break;
            }
          case 2:
          case -1:
            {
              JOptionPane.showMessageDialog(
                  handlerFrame,
                  "Operation was canceled",
                  "DrCleaner",
                  JOptionPane.INFORMATION_MESSAGE);
            }
        }
      }
    }
    return list;
  }
  /**
   * Function that implements deleting algorithm. Function deletes all the files that were found by
   * search and were selected by user to be deleted. At the end function updates the list of files
   * that displayed in Handler window.
   *
   * @param l - list of file with selected files to be deleted
   * @return updated list of files
   */
  @SuppressWarnings({"rawtypes", "serial", "unchecked"})
  public JList<String> deleteFiles(JList<String> l) {
    list = l;
    if (list.getMaxSelectionIndex() == -1)
      JOptionPane.showMessageDialog(
          null,
          "Please select files to be deleted! ",
          "DrCleaner",
          JOptionPane.INFORMATION_MESSAGE);
    else {
      int j =
          JOptionPane.showConfirmDialog(
              null,
              "Are you sure you want to delete selected fles? ",
              "DrCleaner",
              JOptionPane.YES_NO_OPTION);
      if (j == JOptionPane.YES_OPTION) {
        long space = 0;
        int numOfFilesThatCouldntDelete = 0;
        int numOfselected = 0;
        final Vector<String> temp = new Vector<String>();
        for (int i = 0; i < list.getModel().getSize(); i++) {
          if (list.isSelectedIndex(i)) {
            numOfselected++;
            File f = new File((String) list.getModel().getElementAt(i));
            space += f.length();
            try {
              if (!f.delete()) {
                space -= f.length();
                numOfFilesThatCouldntDelete++;
              }
            } catch (SecurityException e) {
              // TODO: handle exception
              e.printStackTrace();
            }
          } else temp.add((String) list.getModel().getElementAt(i));
        }

        list.setModel(
            new javax.swing.AbstractListModel() {
              public int getSize() {
                return temp.size();
              }

              public Object getElementAt(int i) {
                return temp.get(i);
              }
            });
        list.repaint();
        String str =
            "From "
                + numOfselected
                + " selected files, "
                + (numOfselected - numOfFilesThatCouldntDelete)
                + " were deleted\n Total saved space is: "
                + (space / 1024)
                + "KB";
        JOptionPane.showMessageDialog(null, str, "DrCleaner", JOptionPane.INFORMATION_MESSAGE);
        if (temp.isEmpty()) {
          JOptionPane.showMessageDialog(
              handlerFrame,
              "You have no more files to handle",
              "DrCleaner",
              JOptionPane.INFORMATION_MESSAGE);
          handlerFrame.dispose();
        }
      }
    }
    return list;
  }