/**
   * Find tv episodes.
   *
   * @param tvShow the tv show
   * @param dir the dir
   */
  private void findTvEpisodesAsDisc(TvShow tvShow, File dir) {
    String parentDir = dir.getParent();
    LOGGER.debug("parsing disc structure in " + dir.getPath() + " parent: " + parentDir);
    // crawl this folder and try to find every episode in it

    List<MediaFile> videoFiles = new ArrayList<MediaFile>();
    File firstVideoFile = null;

    File[] content = dir.listFiles();
    if (content == null) {
      LOGGER.error("Whops. Cannot access directory: " + dir.getName());
      return;
    }

    for (File file : content) {
      if (file.isFile()) {
        // check filetype
        if (!Globals.settings
                .getVideoFileType()
                .contains("." + FilenameUtils.getExtension(file.getName()).toLowerCase())
            || file.getName().startsWith(skipFilesStartingWith)) { // MacOS ignore
          continue;
        }

        videoFiles.add(new MediaFile(file));
        if (firstVideoFile == null) {
          firstVideoFile = file;
        }
      }
    }

    List<TvShowEpisode> episodes = tvShowList.getTvEpisodesByFile(tvShow, firstVideoFile);
    if (episodes.size() == 0) {
      String relativePath =
          new File(tvShow.getPath()).toURI().relativize(firstVideoFile.toURI()).getPath();
      EpisodeMatchingResult result =
          TvShowEpisodeAndSeasonParser.detectEpisodeFromFilenameAlternative(
              relativePath, tvShow.getTitle());

      if (result.season == -1) {
        // did the search find a season?
        // no -> search for it in the folder name (relative path between tv show root and the
        // current dir)
        result.season = TvShowEpisodeAndSeasonParser.detectSeason(relativePath);
      }

      if (result.episodes.size() == 0) {
        // try to parse out episodes/season from parent directory
        result =
            TvShowEpisodeAndSeasonParser.detectEpisodeFromDirectory(
                dir.getParentFile(), tvShow.getPath());
      }

      List<TvShowEpisode> episodesInNfo = TvShowEpisode.parseNFO(firstVideoFile);

      // FIXME: Episode root is outside of disc folders ?!
      while (dir.getPath().toUpperCase().contains("BDMV")
          || dir.getPath().toUpperCase().contains("VIDEO_TS")) {
        dir = dir.getParentFile();
      }

      if (result.episodes.size() > 0) {
        // add it
        for (int ep : result.episodes) {
          TvShowEpisode episode = null;
          // search in the NFO list if an episode has been found
          for (int i = episodesInNfo.size() - 1; i >= 0; i--) {
            TvShowEpisode e = episodesInNfo.get(i);
            if (e.getSeason() == result.season && e.getEpisode() == ep) {
              episode = e;
              episodesInNfo.remove(i);
              break;
            }
          }
          if (episode == null) {
            episode = new TvShowEpisode();
            episode.setDvdOrder(Globals.settings.getTvShowSettings().isDvdOrder());
            episode.setEpisode(ep);
            episode.setSeason(result.season);
            episode.setNewlyAdded(true);
            episode.setFirstAired(result.date);
          }

          episode.setPath(dir.getPath());
          episode.setTvShow(tvShow);
          episode.setDisc(true);
          episode.setNewlyAdded(true);
          episode.addToMediaFiles(videoFiles);
          episode.setDateAddedFromMediaFile(new MediaFile(firstVideoFile));
          findAdditionalEpisodeFiles(episode, firstVideoFile, content);
          episode.saveToDb();
          tvShow.addEpisode(episode);
        }
      } else {
        // episode detection found nothing - simply add this file
        if (episodesInNfo.size() > 0) {
          for (TvShowEpisode e : episodesInNfo) {
            e.setPath(dir.getPath());
            e.setTvShow(tvShow);
            e.addToMediaFiles(videoFiles);
            e.setNewlyAdded(true);
            // e.findImages();
            e.setDateAddedFromMediaFile(new MediaFile(firstVideoFile));
            findAdditionalEpisodeFiles(e, firstVideoFile, content);
            e.saveToDb();
            tvShow.addEpisode(e);
          }
        } else {
          TvShowEpisode episode = new TvShowEpisode();
          episode.setPath(dir.getPath());
          episode.setDvdOrder(Globals.settings.getTvShowSettings().isDvdOrder());
          episode.setEpisode(-1);
          episode.setSeason(-1);
          episode.setTvShow(tvShow);
          episode.setFirstAired(result.date);
          episode.setDisc(true);
          episode.setNewlyAdded(true);
          episode.addToMediaFiles(videoFiles);
          episode.setDateAddedFromMediaFile(new MediaFile(firstVideoFile));
          findAdditionalEpisodeFiles(episode, firstVideoFile, content);
          episode.saveToDb();
          tvShow.addEpisode(episode);
        }
      }
    } else {
      // episode already added; look if any new additional files have been added
      for (TvShowEpisode episode : episodes) {
        if (findAdditionalEpisodeFiles(episode, firstVideoFile, content)) {
          episode.saveToDb();
        }
      }
    }
  }
  /**
   * Find tv episodes.
   *
   * @param tvShow the tv show
   * @param dir the dir
   */
  private void findTvEpisodes(TvShow tvShow, File dir) {
    LOGGER.debug("parsing " + dir.getPath());
    // crawl this folder and try to find every episode and its corresponding files in it
    File[] content = dir.listFiles();
    if (content == null) {
      LOGGER.error("Whops. Cannot access directory: " + dir.getName());
      return;
    }

    Arrays.sort(content);
    for (File file : content) {
      if (file.isFile()) {
        if (!file.getName().startsWith(skipFilesStartingWith)) {
          MediaFile mf = new MediaFile(file);
          // check filetype - we only proceed here if it's a video file
          if (!mf.getType().equals(MediaFileType.VIDEO)) {
            continue;
          }

          // is this file already assigned to another episode?
          List<TvShowEpisode> episodes = tvShowList.getTvEpisodesByFile(tvShow, file);
          if (episodes.size() == 0) {
            // try to check what episode//season
            // EpisodeMatchingResult result =
            // TvShowEpisodeAndSeasonParser.detectEpisodeFromFilename(file);
            String relativePath =
                new File(tvShow.getPath()).toURI().relativize(file.toURI()).getPath();
            EpisodeMatchingResult result =
                TvShowEpisodeAndSeasonParser.detectEpisodeFromFilenameAlternative(
                    relativePath, tvShow.getTitle());

            // second check: is the detected episode (>-1; season >-1) already in tmm and any valid
            // stacking markers found?
            if (result.episodes.size() == 1 && result.season > -1 && result.stackingMarkerFound) {
              // get any assigned episode
              TvShowEpisode ep = tvShow.getEpisode(result.season, result.episodes.get(0));
              if (ep != null) {
                ep.setNewlyAdded(true);
                ep.addToMediaFiles(mf);
                continue;
              }
            }

            if (result.episodes.size() == 0) {
              // try to parse out episodes/season from parent directory
              result =
                  TvShowEpisodeAndSeasonParser.detectEpisodeFromDirectory(dir, tvShow.getPath());
            }

            if (result.season == -1) {
              // did the search find a season?
              // no -> search for it in the folder name (relative path between tv show root and the
              // current dir)
              result.season = TvShowEpisodeAndSeasonParser.detectSeason(relativePath);
            }

            List<TvShowEpisode> episodesInNfo = TvShowEpisode.parseNFO(file);

            // did we find any episodes in the NFO?
            if (episodesInNfo.size() > 0) {
              // these have priority!
              for (TvShowEpisode e : episodesInNfo) {
                e.setPath(dir.getPath());
                e.setTvShow(tvShow);
                e.addToMediaFiles(mf);
                e.setDateAddedFromMediaFile(mf);
                findAdditionalEpisodeFiles(e, file, content);
                e.setNewlyAdded(true);
                e.saveToDb();
                tvShow.addEpisode(e);
              }
            } else if (result.episodes.size() > 0) {
              // something found with the season detection?
              for (int ep : result.episodes) {
                TvShowEpisode episode = new TvShowEpisode();
                episode.setDvdOrder(Globals.settings.getTvShowSettings().isDvdOrder());
                episode.setEpisode(ep);
                episode.setSeason(result.season);
                episode.setFirstAired(result.date);

                if (result.name.isEmpty()) {
                  result.name = FilenameUtils.getBaseName(file.getName());
                }
                episode.setTitle(result.name);

                episode.setPath(dir.getPath());
                episode.setTvShow(tvShow);
                episode.addToMediaFiles(mf);
                episode.setDateAddedFromMediaFile(mf);
                findAdditionalEpisodeFiles(episode, file, content);
                episode.setNewlyAdded(true);
                episode.saveToDb();
                tvShow.addEpisode(episode);
              }
            } else {
              // episode detection found nothing - simply add this file
              TvShowEpisode episode = new TvShowEpisode();
              episode.setDvdOrder(Globals.settings.getTvShowSettings().isDvdOrder());
              episode.setEpisode(-1);
              episode.setSeason(-1);
              episode.setPath(dir.getPath());

              episode.setTitle(FilenameUtils.getBaseName(file.getName()));
              episode.setTvShow(tvShow);
              episode.setFirstAired(result.date);
              episode.addToMediaFiles(mf);
              episode.setDateAddedFromMediaFile(mf);
              findAdditionalEpisodeFiles(episode, file, content);
              episode.setNewlyAdded(true);
              episode.saveToDb();
              tvShow.addEpisode(episode);
            }
          } else {
            // episode already added; look if any new additional files have been added
            for (TvShowEpisode episode : episodes) {
              if (findAdditionalEpisodeFiles(episode, file, content)) {
                episode.saveToDb();
              }
            }
          }
        } // end skipFilesStartingWith
      } // end isFile

      if (file.isDirectory()
          && !skipFolders.contains(file.getName().toUpperCase())
          && !file.getName().matches(skipFoldersRegex)
          && !TvShowModuleManager.TV_SHOW_SETTINGS
              .getTvShowSkipFolders()
              .contains(file.getAbsolutePath())) {
        // check if that directory contains a .tmmignore file
        File tmmIgnore = new File(file, ".tmmignore");
        if (!tmmIgnore.exists()) {
          // dig deeper
          if (file.getName().toUpperCase().equals("VIDEO_TS")) {
            findTvEpisodesAsDisc(tvShow, file);
          } else if (file.getName().toUpperCase().equals("BDMV")) {
            findTvEpisodesAsDisc(tvShow, file);
          } else {
            findTvEpisodes(tvShow, file);
          }
        }
      }
    }
  }