// SKOKODoc.cpp : implementation of the CSKOKODoc class
//

#include "stdafx.h"
#include "SKOKO.h"
#include "MainFrm.h"
#include "BGDNet.h"
#include "Traversal.h"
#include "SKOKOView.h"
#include "ErrView.h"
#include "SKOKODoc.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CSKOKODoc

IMPLEMENT_DYNCREATE(CSKOKODoc, CDocument)

BEGIN_MESSAGE_MAP(CSKOKODoc, CDocument)
  //{{AFX_MSG_MAP(CSKOKODoc)
  ON_COMMAND(ID_VIEW_REFRESH, OnViewRefresh)
  ON_COMMAND(ID_FILE_SAVE_ERR_LOG, OnFileSaveErrLog)
  ON_COMMAND(ID_FILE_SAVE_VALID_LOG, OnFileSaveValidLog)
  ON_UPDATE_COMMAND_UI(ID_FILE_SAVE_ERR_LOG, OnUpdateFileSaveErrLog)
  ON_UPDATE_COMMAND_UI(ID_FILE_SAVE_VALID_LOG, OnUpdateFileSaveValidLog)
  ON_UPDATE_COMMAND_UI(ID_VIEW_REFRESH, OnUpdateViewRefresh)
	ON_COMMAND(ID_OPERATION_SCAN, OnOperationScan)
	ON_COMMAND(ID_OPERATION_ASSIGNATION, OnOperationAssignation)
	ON_UPDATE_COMMAND_UI(ID_OPERATION_ASSIGNATION, OnUpdateOperationAssignation)
	ON_COMMAND(ID_OPERATION_AUTOMAT, OnOperationAutomat)
	ON_UPDATE_COMMAND_UI(ID_OPERATION_AUTOMAT, OnUpdateOperationAutomat)
	ON_UPDATE_COMMAND_UI(ID_FILE_OPEN, OnUpdateFileOpen)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CSKOKODoc construction/destruction

CSKOKODoc::CSKOKODoc() : m_dirSelected(FALSE)
{
  // TODO: add one-time construction code here

}

CSKOKODoc::~CSKOKODoc()
{
}

/////////////////////////////////////////////////////////////////////////////
// CSKOKODoc serialization


/////////////////////////////////////////////////////////////////////////////
// CSKOKODoc diagnostics

#ifdef _DEBUG
void CSKOKODoc::AssertValid() const
{
  CDocument::AssertValid();
}

void CSKOKODoc::Dump(CDumpContext& dc) const
{
  CDocument::Dump(dc);
}
#endif //_DEBUG

/////////////////////////////////////////////////////////////////////////////
// CSKOKODoc commands

void CSKOKODoc::RefreshFileList( void )
{
  m_fileListing.reset();

  CMainFrame* pFrameWnd = theApp.FrameWnd();
  CFileListingFormation traversal(&m_fileListing);
  traversal.run(m_currentDir, true, pFrameWnd);

  // Заполняем ComboBox с owner-ами:
  GetOwners();

  // Выбираем владельца и заполняем View:
  pFrameWnd->SelectOwner();
}

void CSKOKODoc::SetOwner( LPCTSTR newOwner )
{
  CString s = newOwner;
  if (s == _T(ALL_OWNERS))
      s.Empty();
  //if (s != m_owner)
  {
    m_owner = s;
    UpdateAllViews(NULL, 11);
  }
}

void CSKOKODoc::OnViewRefresh() 
{
  ScanDir();
}

BOOL CSKOKODoc::CheckDiskSpace( LPCTSTR path )
{
  if (m_diskSpaceDlg.m_noMore)
    return TRUE;
  else
  {
    TCHAR drive[_MAX_DRIVE];
    TCHAR dir[_MAX_DIR];
    TCHAR fname[_MAX_FNAME];
    TCHAR ext[_MAX_EXT];

    _tsplitpath(path, drive, dir, fname, ext);
    ULARGE_INTEGER freeBytesAvailable;
    ULARGE_INTEGER totalNumberOfBytes;
    ULARGE_INTEGER totalNumberOfFreeBytes;
    BOOL ok = GetDiskFreeSpaceEx(
      drive,
      &freeBytesAvailable,
      &totalNumberOfBytes,
      &totalNumberOfFreeBytes);
    if (ok)
    {
      const unsigned bytesPerRec = 512;
      unsigned availRecs = freeBytesAvailable.QuadPart/bytesPerRec;
      if (availRecs > 10000)
        availRecs = 1000*(availRecs/1000);
      else if (availRecs > 1000)
        availRecs = 100*(availRecs/100);
      if (availRecs < 300000)
      {
        m_diskSpaceDlg.m_warningText.Format(
          _T("На диске %s доступно %I64u байт. Этого достаточно для хранения ")
          _T("около %u записей максимального размера.\r\nВы хотите продолжить?"),
          drive,
          freeBytesAvailable.QuadPart,
          availRecs);
        return IDOK == m_diskSpaceDlg.DoModal();
      }
    }

    return TRUE;
  }
}

void CSKOKODoc::OnFileSaveErrLog() 
{
  CFileDialog dlg(FALSE);
  if (IDOK == dlg.DoModal())
  {
    CWaitCursor wc;
    CLog saveLog;
    saveLog.Create(dlg.GetPathName(), false);
    for (int i = 0; i < m_fileListing.errCount(); ++i)
    {
      CFileInfo fi;
      m_fileListing.errAt(i, &fi);
      saveLog.Append(fi);
    }
    saveLog.Close();
    AfxMessageBox(_T("Файл сохранен"), MB_ICONINFORMATION);
  }
}

void CSKOKODoc::OnFileSaveValidLog() 
{
  CFileDialog dlg(FALSE);
  if (IDOK == dlg.DoModal())
  {
    CWaitCursor wc;
    CLog saveLog;
    saveLog.Create(dlg.GetPathName(), false);
    for (int i = 0; i < m_fileListing.fileCount(); ++i)
    {
      CFileInfo fi;
      m_fileListing.fileAt(i, &fi);
      if (m_owner.IsEmpty() || m_owner == fi.ownerName)
        saveLog.Append(fi);
    }
    saveLog.Close();
    AfxMessageBox(_T("Файл сохранен"), MB_ICONINFORMATION);
  }
}

void CSKOKODoc::OnUpdateFileSaveErrLog(CCmdUI* pCmdUI) 
{
  pCmdUI->Enable(m_fileListing.errCount() > 0);
}

void CSKOKODoc::OnUpdateFileSaveValidLog(CCmdUI* pCmdUI) 
{
  pCmdUI->Enable(m_fileListing.fileCount() > 0);
}

void CSKOKODoc::Clear( void )
{
  UpdateAllViews(NULL, 10);
  m_owner.Empty();
  m_dirSelected = FALSE;
  m_fileListing.reset();
  CMainFrame* pFrameWnd = theApp.FrameWnd();
  pFrameWnd->SetCountIndicator(0, 0);
  pFrameWnd->SetErrIndicator(0);
  pFrameWnd->SetSizeIndicator(0, 0);
}

void CSKOKODoc::OnUpdateViewRefresh(CCmdUI* pCmdUI) 
{
  pCmdUI->Enable(m_dirSelected);
}

BOOL CSKOKODoc::OnOpenDocument(LPCTSTR lpszPathName)
{
  CMainFrame* pFrameWnd = theApp.FrameWnd();
  pFrameWnd->SetCountIndicator(0, 0);
  pFrameWnd->SetErrIndicator(0);
  pFrameWnd->SetSizeIndicator(0, 0);
  UpdateAllViews(NULL, 10);

  m_fileListing.load(lpszPathName);

  // Заполняем ComboBox с owner-ами:
  GetOwners();

  // Выбираем владельца и заполняем View:
  pFrameWnd->SelectOwner();

  m_dirSelected = FALSE;

  return TRUE;
}

void CSKOKODoc::GetOwners( void )
{
  CMainFrame* pFrameWnd = theApp.FrameWnd();
  pFrameWnd->RemoveAllOwners();
  pFrameWnd->AddOwner(ALL_OWNERS); // это значит "все"
  POSITION pos = m_fileListing.firstOwnerPos();
  while (pos)
    pFrameWnd->AddOwner(m_fileListing.nextOwnerName(pos));
}

void CSKOKODoc::OnOperationScan() 
{
  if (IDOK == m_dirListDlg.DoModal())
  {
    if (CheckDiskSpace(theApp.m_tempDir))
    {
      m_dirSelected = TRUE;
      m_currentDir = m_dirListDlg.SelectedDir();
      CString sSel = m_currentDir;
      if (sSel.IsEmpty())
        sSel = _T("Вся сеть");
      SetPathName(sSel, FALSE);
      SetTitle(sSel);
      ScanDir();
    }
  }
}

void CSKOKODoc::OnOperationAssignation() 
{
  if (GetFileView()->GetSelectedFileCount() > 0)
    m_assignDlg.m_selectFiles = 1; // Выделенные файлы
  else if (m_fileListing.fileCount() > 0)
    m_assignDlg.m_selectFiles = 0; // Все файлы
  else
    m_assignDlg.m_selectFiles = 2; // Файлы в каталоге
	if (IDOK == m_assignDlg.DoModal() && !m_assignDlg.m_newOwner.IsEmpty())
  {
    if (CheckDiskSpace(theApp.m_tempDir))
    {
      m_fileListing.resetErrors();
      GetErrView()->Reset();

      UpdateAllViews(NULL);

      switch (m_assignDlg.m_selectFiles)
      {
        case 0: // Весь список
          AssignAllFiles();
          break;
        case 1: // Выделенные файлы
          AssignSelectedFiles();
          break;
        case 2: // Файлы в каталоге
        {
          m_dirSelected = TRUE;
          m_currentDir = m_assignDlg.m_startDir;
          CString sSel = m_currentDir;
          if (sSel.IsEmpty())
            sSel = _T("Вся сеть");
          SetPathName(sSel, FALSE);
          SetTitle(sSel);
          AssignFilesInDir();
          break;
        }
      }

      // Найти и обновить CSKOKOView:
      CRuntimeClass* pFileViewClass = RUNTIME_CLASS(CSKOKOView);
      POSITION pos = GetFirstViewPosition();
      while (pos != NULL)
      {
        CView* pView = GetNextView(pos);
        pView->Invalidate();
      }

      // Обновить список владельцев:
      RefreshOwnerCombo();
      if (!Owner().IsEmpty() && m_assignDlg.m_newOwner.CompareNoCase(Owner()))
      {
        theApp.FrameWnd()->HideOwner();
      }
    }
  }
}

void CSKOKODoc::OnUpdateOperationAssignation(CCmdUI* pCmdUI) 
{
  pCmdUI->Enable(theApp.IsAdminMode());
}

void CSKOKODoc::OnOperationAutomat() 
{
  if (IDOK == m_dirListDlg.DoModal())
  {
    if (CheckDiskSpace(theApp.m_tempDir))
    {
      m_dirSelected = TRUE;
      m_currentDir = m_dirListDlg.SelectedDir();
      CString sSel = m_currentDir;
      if (sSel.IsEmpty())
        sSel = _T("Вся сеть");
      SetPathName(sSel, FALSE);
      SetTitle(sSel);
      AutoRepair();
    }
  }
}

void CSKOKODoc::OnUpdateOperationAutomat(CCmdUI* pCmdUI) 
{
  pCmdUI->Enable(theApp.IsAdminMode());
}

void CSKOKODoc::ScanDir()
{
  if (m_dirSelected)
  {
    CMainFrame* pFrameWnd = theApp.FrameWnd();
    
    // Очистить все:
    pFrameWnd->SetCountIndicator(0, 0);
    pFrameWnd->SetErrIndicator(0);
    pFrameWnd->SetSizeIndicator(0, 0);
    UpdateAllViews(NULL, 10);
    
    // Обновить списки:
    RefreshFileList();
  }
}

void CSKOKODoc::AutoRepair()
{
  if (!m_dirSelected)
    return;

  CMainFrame* pFrameWnd = theApp.FrameWnd();

  pFrameWnd->SetCountIndicator(0, 0);
  pFrameWnd->SetErrIndicator(0);
  pFrameWnd->SetSizeIndicator(0, 0);

  UpdateAllViews(NULL, 10);

  m_fileListing.reset();
  CRepairOwnerModifier repair(m_ctx);
  CGlobalFileAttrUpdate traversal(&m_fileListing, &repair);
  traversal.run(m_currentDir, true, pFrameWnd);

  // Заполняем ComboBox с owner-ами:
  GetOwners();

  // Выбираем владельца и заполняем View:
  pFrameWnd->SelectOwner();
}

void CSKOKODoc::AssignFilesInDir()
{
  if (!m_dirSelected)
    return;

  CMainFrame* pFrameWnd = theApp.FrameWnd();

  pFrameWnd->SetCountIndicator(0, 0);
  pFrameWnd->SetErrIndicator(0);
  pFrameWnd->SetSizeIndicator(0, 0);

  UpdateAllViews(NULL, 10);

  m_fileListing.reset();
  CChangeOwner change(
    m_ctx,
    m_assignDlg.m_anyOwner ? _T("") : m_assignDlg.m_curOwner,
    m_assignDlg.m_newOwner);
  CGlobalFileAttrUpdate traversal(&m_fileListing, &change);
  traversal.run(m_currentDir, m_assignDlg.m_recursive == TRUE, pFrameWnd);

  // Заполняем ComboBox с owner-ами:
  GetOwners();

  // Выбираем владельца и заполняем View:
  pFrameWnd->SelectOwner();
}

void CSKOKODoc::AssignAllFiles( void )
{
  CChangeOwner change(
    m_ctx,
    m_assignDlg.m_anyOwner ? _T("") : m_assignDlg.m_curOwner,
    m_assignDlg.m_newOwner);
  GetFileView()->UpdateAllFiles(&change);
}

void CSKOKODoc::AssignSelectedFiles( void )
{
  CChangeOwner change(
    m_ctx,
    m_assignDlg.m_anyOwner ? _T("") : m_assignDlg.m_curOwner,
    m_assignDlg.m_newOwner);
  GetFileView()->UpdateSelectedFiles(&change);
}

CSKOKOView* CSKOKODoc::GetFileView( void )
{
  CRuntimeClass* pFileViewClass = RUNTIME_CLASS(CSKOKOView);
  POSITION pos = GetFirstViewPosition();
  while (pos != NULL)
  {
    CView* pView = GetNextView(pos);
    if (pView->IsKindOf(pFileViewClass))
      return (CSKOKOView*)pView;
  }
  return NULL;
}

CErrView* CSKOKODoc::GetErrView( void )
{
  CRuntimeClass* pErrViewClass = RUNTIME_CLASS(CErrView);
  POSITION pos = GetFirstViewPosition();
  while (pos != NULL)
  {
    CView* pView = GetNextView(pos);
    if (pView->IsKindOf(pErrViewClass))
      return (CErrView*)pView;
  }
  return NULL;
}

void CSKOKODoc::RefreshOwnerCombo( void )
{
  CMainFrame* pFrameWnd = theApp.FrameWnd();
  POSITION pos = m_fileListing.firstOwnerPos();
  while (pos)
    pFrameWnd->EnsureOwnerExists(m_fileListing.nextOwnerName(pos));
}

void CSKOKODoc::GetFileInfo(int n, CFileInfo *pInfo) const
{
  m_fileListing.fileAt(n, pInfo);
}

int CSKOKODoc::GetErrorCount() const
{
  return m_fileListing.errCount();
}

void CSKOKODoc::GetErrorInfo(int n, CFileInfo *pInfo) const
{
  m_fileListing.errAt(n, pInfo);
}

int CSKOKODoc::GetFileCount() const
{
  return m_fileListing.fileCount();
}

void CSKOKODoc::UpdateFileInfo(int n, const CFileInfo &fi)
{
  m_fileListing.updateFileAt(n, fi);
}

void CSKOKODoc::AddErrorInfo(const CFileInfo &info)
{
  m_fileListing.addError(info);
}

void CSKOKODoc::RefreshErrView()
{
  GetErrView()->Refresh();
}

void CSKOKODoc::OnUpdateFileOpen(CCmdUI* pCmdUI) 
{
  //pCmdUI->Enable(theApp.IsAdminMode());
	pCmdUI->Enable(TRUE);
}
