text: ﻿using System.Collections.ObjectModel;
  using System.Linq;
  using System.Threading.Tasks;
  using System.Windows.Input;
  using VersOne.Epub.WpfDemo.Models;
  using VersOne.Epub.WpfDemo.Utils;
  
  namespace VersOne.Epub.WpfDemo.ViewModels
  {
      public class BookViewModel : ViewModel
      {
          private readonly BookModel bookModel;
  
          private bool isLoading;
          private ObservableCollection<NavigationItemViewModel> navigation;
          private ObservableCollection<HtmlContentFileViewModel> readingOrder;
          private HtmlContentFileViewModel currentHtmlContentFile;
          private HtmlContentFileViewModel previousHtmlContentFile;
          private HtmlContentFileViewModel nextHtmlContentFile;
          private string currentAnchor;
          private Command navigateCommand;
          private Command previousCommand;
          private Command nextCommand;
  
          public BookViewModel(int bookId)
          {
              bookModel = new BookModel();
              isLoading = true;
              currentHtmlContentFile = null;
              previousHtmlContentFile = null;
              nextHtmlContentFile = null;
              currentAnchor = null;
              navigateCommand = null;
              previousCommand = null;
              nextCommand = null;
              bookModel.OpenBookAsync(bookId).ContinueWith(epubBook => BookOpened(epubBook), TaskScheduler.FromCurrentSynchronizationContext());
          }
  
          public ObservableCollection<NavigationItemViewModel> Navigation
          {
              get
              {
                  return navigation;
              }
              private set
              {
                  navigation = value;
                  NotifyPropertyChanged();
              }
          }
  
          public ObservableCollection<HtmlContentFileViewModel> ReadingOrder
          {
              get
              {
                  return readingOrder;
              }
              private set
              {
                  readingOrder = value;
                  NotifyPropertyChanged();
              }
          }
  
          public bool IsLoading
          {
              get
              {
                  return isLoading;
              }
              private set
              {
                  isLoading = value;
                  NotifyPropertyChanged();
              }
          }
  
          public HtmlContentFileViewModel CurrentHtmlContentFile
          {
              get
              {
                  return currentHtmlContentFile;
              }
              set
              {
                  currentHtmlContentFile = value;
                  NotifyPropertyChanged();
              }
          }
  
          public bool IsPreviousButtonVisible
          {
              get
              {
                  return previousHtmlContentFile != null;
              }
          }
  
          public bool IsNextButtonVisible
          {
              get
              {
                  return nextHtmlContentFile != null;
              }
          }
  
          public string CurrentAnchor
          {
              get
              {
                  return currentAnchor;
              }
              set
              {
                  currentAnchor = value;
                  NotifyPropertyChanged();
              }
          }
  
          public ICommand NavigateCommand
          {
              get
              {
                  if (navigateCommand == null)
                  {
                      navigateCommand = new Command(param => Navigate(param as NavigationItemViewModel));
                  }
                  return navigateCommand;
              }
          }
  
          public ICommand PreviousCommand
          {
              get
              {
                  if (previousCommand == null)
                  {
                      previousCommand = new Command(NavigateToPreviousItemInReadingOrder);
                  }
                  return previousCommand;
              }
          }
  
          public ICommand NextCommand
          {
              get
              {
                  if (nextCommand == null)
                  {
                      nextCommand = new Command(NavigateToNextItemInReadingOrder);
                  }
                  return nextCommand;
              }
          }
  
          private void BookOpened(Task<EpubBook> task)
          {
              EpubBook epubBook = task.Result;
              Navigation = new ObservableCollection<NavigationItemViewModel>(bookModel.GetNavigation(epubBook));
              ReadingOrder = new ObservableCollection<HtmlContentFileViewModel>(bookModel.GetReadingOrder(epubBook));
              if (ReadingOrder.Any())
              {
                  CurrentHtmlContentFile = ReadingOrder.First();
                  if (ReadingOrder.Count > 1)
                  {
                      nextHtmlContentFile = ReadingOrder[1];
                  }
              }
              IsLoading = false;
              NotifyPropertyChanged(nameof(IsPreviousButtonVisible));
              NotifyPropertyChanged(nameof(IsNextButtonVisible));
          }
  
          private void Navigate(NavigationItemViewModel navigationItemViewModel)
          {
              navigationItemViewModel.IsTreeItemExpanded = true;
              if (navigationItemViewModel.IsLink)
              {
                  Navigate(ReadingOrder.FirstOrDefault(htmlContentFile => htmlContentFile.HtmlFilePath == navigationItemViewModel.FilePath));
                  CurrentAnchor = navigationItemViewModel.Anchor;
              }
          }
  
          private void Navigate(HtmlContentFileViewModel targetHtmlContentFileViewModel)
          {
              if (targetHtmlContentFileViewModel == null)
              {
                  CurrentHtmlContentFile = null;
                  previousHtmlContentFile = null;
                  nextHtmlContentFile = null;
              }
              else if (CurrentHtmlContentFile != targetHtmlContentFileViewModel)
              {
                  CurrentHtmlContentFile = targetHtmlContentFileViewModel;
                  int currentReadingOrderItemIndex = ReadingOrder.IndexOf(CurrentHtmlContentFile);
                  if (currentReadingOrderItemIndex != -1)
                  {
                      if (currentReadingOrderItemIndex > 0)
                      {
                          previousHtmlContentFile = ReadingOrder[currentReadingOrderItemIndex - 1];
                      }
                      else
                      {
                          previousHtmlContentFile = null;
                      }
                      if (currentReadingOrderItemIndex < ReadingOrder.Count - 1)
                      {
                          nextHtmlContentFile = ReadingOrder[currentReadingOrderItemIndex + 1];
                      }
                      else
                      {
                          nextHtmlContentFile = null;
                      }
                  }
                  else
                  {
                      previousHtmlContentFile = null;
                      nextHtmlContentFile = null;
                  }
              }
              NotifyPropertyChanged(nameof(IsPreviousButtonVisible));
              NotifyPropertyChanged(nameof(IsNextButtonVisible));
          }
  
          private void NavigateToPreviousItemInReadingOrder()
          {
              if (previousHtmlContentFile != null)
              {
                  Navigate(previousHtmlContentFile);
              }
          }
  
          private void NavigateToNextItemInReadingOrder()
          {
              if (nextHtmlContentFile != null)
              {
                  Navigate(nextHtmlContentFile);
              }
          }
      }
  }
  