// Created on: 2021-04-27
// Created by: Natalia ERMOLAEVA
// Copyright (c) 2021 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement. 

#include <inspector/MessageView_ActionsTest.hxx>

#include <inspector/MessageModel_ItemReport.hxx>
#include <inspector/MessageModel_ItemRoot.hxx>
#include <inspector/MessageModel_ItemAlert.hxx>
#include <inspector/MessageModel_TreeModel.hxx>
#include <inspector/ViewControl_Tools.hxx>

#include <Message.hxx>
#include <Message_AlertExtended.hxx>
#include <Message_Level.hxx>
#include <Message_Messenger.hxx>

#include <gp_Ax1.hxx>
#include <gp_Ax2.hxx>
#include <gp_Ax3.hxx>
#include <Bnd_Box.hxx>
#include <Bnd_OBB.hxx>
#include <BRepBuilderAPI_MakeEdge.hxx>
#include <OSD_Chronometer.hxx>
#include <Quantity_Color.hxx>
#include <Quantity_ColorRGBA.hxx>
#include <TCollection_AsciiString.hxx>
#include <TopoDS_AlertAttribute.hxx>

#include <Standard_WarningsDisable.hxx>
#include <QAction>
#include <QFileDialog>
#include <QItemSelectionModel>
#include <QMenu>
#include <QMessageBox>
#include <QWidget>
#include <Standard_WarningsRestore.hxx>

#include <ctime>

// =======================================================================
// function : Constructor
// purpose :
// =======================================================================
MessageView_ActionsTest::MessageView_ActionsTest (QWidget* theParent,
  MessageModel_TreeModel* theTreeModel, QItemSelectionModel* theModel)
: QObject (theParent), myTreeModel (theTreeModel), mySelectionModel (theModel)
{
  myActions.insert (MessageModel_ActionType_TestMetric,
                    ViewControl_Tools::CreateAction ("Test <metric>", SLOT (OnTestMetric()), parent(), this));
  myActions.insert (MessageModel_ActionType_TestMessenger,
                    ViewControl_Tools::CreateAction ("Test <Message_Messenger>", SLOT (OnTestMessenger()), parent(), this));
  myActions.insert (MessageModel_ActionType_TestReportTree,
                    ViewControl_Tools::CreateAction ("Test <Tree of messages>", SLOT (OnTestReportTree()), parent(), this));
}

// =======================================================================
// function : AddMenuActions
// purpose :
// =======================================================================
void MessageView_ActionsTest::AddMenuActions (const QModelIndexList& theSelectedIndices, QMenu* theMenu)
{
  MessageModel_ItemReportPtr aReportItem;
  for (QModelIndexList::const_iterator aSelIt = theSelectedIndices.begin(); aSelIt != theSelectedIndices.end(); aSelIt++)
  {
    QModelIndex anIndex = *aSelIt;
    if (anIndex.column() != 0)
      continue;

    TreeModel_ItemBasePtr anItemBase = TreeModel_ModelBase::GetItemByIndex (anIndex);
    if (!anItemBase)
      continue;

    MessageModel_ItemRootPtr aRootItem = itemDynamicCast<MessageModel_ItemRoot> (anItemBase);
    if (aRootItem)
      continue;

    aReportItem = itemDynamicCast<MessageModel_ItemReport> (anItemBase);
    if (aReportItem)
      break;

    MessageModel_ItemAlertPtr anAlertItem = itemDynamicCast<MessageModel_ItemAlert> (anItemBase);
    if (anAlertItem)
      continue;
  }

  if (aReportItem && !aReportItem->GetReport().IsNull())
  {
    theMenu->addAction (myActions[MessageModel_ActionType_TestMetric]);
    theMenu->addAction (myActions[MessageModel_ActionType_TestMessenger]);
    theMenu->addAction (myActions[MessageModel_ActionType_TestReportTree]);

    bool isReportEnabled = aReportItem->GetReport()->IsActiveInMessenger();
    myActions[MessageModel_ActionType_TestMetric]->setEnabled (isReportEnabled);
    myActions[MessageModel_ActionType_TestMessenger]->setEnabled (isReportEnabled);
    myActions[MessageModel_ActionType_TestReportTree]->setEnabled (isReportEnabled);
  }
  theMenu->addSeparator();
}

// =======================================================================
// function : getSelectedReport
// purpose :
// =======================================================================
Handle(Message_Report) MessageView_ActionsTest::getSelectedReport (QModelIndex& theReportIndex) const
{
  MessageModel_ItemReportPtr aReportItem;
  QModelIndexList aSelectedIndices = mySelectionModel->selectedIndexes();
  for (QModelIndexList::const_iterator aSelIt = aSelectedIndices.begin(); aSelIt != aSelectedIndices.end(); aSelIt++)
  {
    QModelIndex anIndex = *aSelIt;
    if (anIndex.column() != 0)
      continue;

    TreeModel_ItemBasePtr anItemBase = TreeModel_ModelBase::GetItemByIndex (anIndex);
    if (!anItemBase)
      continue;

    aReportItem = itemDynamicCast<MessageModel_ItemReport> (anItemBase);
    theReportIndex = anIndex;
    if (aReportItem)
      break;
  }
  if (!aReportItem)
    return NULL;

  return aReportItem->GetReport();
}

// =======================================================================
// function : OnTestMetric
// purpose :
// =======================================================================
void MessageView_ActionsTest::OnTestMetric()
{
  QModelIndex aReportIndex;
  Handle(Message_Report) aReport = getSelectedReport (aReportIndex);
  if (aReport.IsNull())
    return;

  OCCT_ADD_MESSAGE_LEVEL_SENTRY ("MessageModel_Actions::OnTestMetric()");
  clock_t start_time =  clock();

  Standard_Integer aCounter = 1500;
  Standard_Real aValue = 0., aValue2 = 0.1;

  for (int aTopIt = 0; aTopIt < 4; aTopIt++)
  {
    Message::SendInfo() << "Calculate";
    for (int j = 0; j < aCounter; j++)
    {
      for (int i = 0; i < aCounter; i++)
      {
        aValue = (aValue * 2. + 3.) * 0.5 - 0.3 * 0.5;

        Standard_Real aValue3 = aValue + aValue2 * 0.2;
        (void)aValue3;
      }
    }
  }

  myTreeModel->UpdateTreeModel();

  clock_t end_time = clock();
  std::cout << "clock() = " << end_time - start_time << std::endl;
}

// =======================================================================
// function : createShapeOnLevel
// purpose :
// =======================================================================
void createShapeOnLevel()
{
  OCCT_ADD_MESSAGE_LEVEL_SENTRY ("createShapeOnLevel")

  Message_Messenger::StreamBuffer sout = Message::SendInfo();

  BRepBuilderAPI_MakeEdge aBuilder (gp_Pnt (0., 0., 0.), gp_Pnt (20., 10., 20.));
  TopoDS_Shape aShape = aBuilder.Shape();

  Message::DefaultMessenger() << aShape;
}

// =======================================================================
// function : createShape
// purpose :
// =======================================================================
void createShape()
{
  Message_Messenger::StreamBuffer sout = Message::SendInfo();
  BRepBuilderAPI_MakeEdge aBuilder (gp_Pnt (0., 0., 0.), gp_Pnt (20., 10., 20.));
  TopoDS_Shape aShape = aBuilder.Shape();

  Message::DefaultMessenger() << aShape;
  createShapeOnLevel();
}

// =======================================================================
// function : OnTestMessenger
// purpose :
// =======================================================================
void MessageView_ActionsTest::OnTestMessenger()
{
  // string messages
  OCCT_ADD_MESSAGE_LEVEL_SENTRY ("MessageModel_Actions::OnTestMessenger()")

  Message::DefaultMessenger()->Send ("Values");
  Message::DefaultMessenger()->Send ("Values second");

  Message_Messenger::StreamBuffer sout = Message::SendInfo();
  // gp_XYZ
  {
    gp_XYZ aCoords (1.3, 2.3, 3.4);
    aCoords.DumpJson (sout);
    sout.Flush(Standard_True);
  }
  // gp_Dir
  {
    gp_Dir aDir (0.3, 0.3, 0.4);
    aDir.DumpJson (sout);
    sout.Flush(Standard_True);
  }
  // gp_Ax1
  {
    gp_Ax1 aCoords (gp_Pnt (1.3, 2.3, 3.4), gp_Dir (0.3, 0.3, 0.4));
    aCoords.DumpJson (sout);
    sout.Flush(Standard_True);
  }
  // gp_Ax2
  {
    gp_Ax2 aCoords (gp_Pnt (10.3, 20.3, 30.4), gp_Dir (0.3, 0.3, 0.4));
    aCoords.DumpJson (sout);
    sout.Flush(Standard_True);
  }
  // gp_Ax3
  {
    gp_Ax3 aPln (gp_Pnt (10., 20., 15.), gp_Dir (0., 0., 1.), gp_Dir (1., 0., 0.));
    aPln.DumpJson (sout);
    sout.Flush(Standard_True);
  }
  // gp_Trsf
  {
    gp_Trsf aTrsf;
    aTrsf.SetRotation (gp::OZ(), 0.3);
    aTrsf.SetTranslationPart (gp_Vec (15., 15., 15.));
    aTrsf.SetScaleFactor (3.);

    aTrsf.DumpJson (sout);
    sout.Flush(Standard_True);
  }
  // Bnd_Box
  {
    Bnd_Box aBox (gp_Pnt (20., 15., 10.), gp_Pnt (25., 20., 15.));
    aBox.DumpJson (sout);
    sout.Flush (Standard_True);
  }
  // Bnd_OBB
  {
    Bnd_OBB anOBB (gp_Pnt (-10., -15., -10.), gp_Dir (1., 0., 0.), gp_Dir (0., 1., 0.), gp_Dir (0., 0., 1.),
                  5., 10., 5.);
    anOBB.DumpJson (sout);
    sout.Flush (Standard_True);
  }
  // Quantity_ColorRGBA
  {
    Quantity_ColorRGBA aColor (0.2f, 0.8f, 0.8f, 0.2f);
    aColor.DumpJson (sout);
    sout.Flush (Standard_True);
  }
  // Quantity_Color
  {
    Quantity_Color aColor (0.8, 0.8, 0.8, Quantity_TOC_RGB);
    aColor.DumpJson (sout);
    sout.Flush (Standard_True);
  }
  //shape messages
  {
    createShape();
  }
  myTreeModel->UpdateTreeModel();
}

// =======================================================================
// function : levelAlerts
// purpose :
// =======================================================================
void levelAlerts (const int theCurrentLevel, const int theTopLevel)
{
  if (theTopLevel - theCurrentLevel <= 0)
    return;

  OCCT_ADD_MESSAGE_LEVEL_SENTRY (TCollection_AsciiString ("Level: " ) + theCurrentLevel)

  Message_Messenger::StreamBuffer sout = Message::SendInfo();
  sout << "Alert(" << theCurrentLevel << "): " << 1 << ", " << 2 << std::endl;
  sout << "Alert(" << theCurrentLevel << "): " << 3 << ", " << 4 << std::endl;

  levelAlerts (theCurrentLevel + 1, theTopLevel);

  sout << "Alert(" << theCurrentLevel << "): " << 4 << ", " << 5 << std::endl;
}

// =======================================================================
// function : levelAlert
// purpose :
// =======================================================================
void levelAlert (const int theCurrentLevel, const int theTopLevel)
{
  if (theTopLevel - theCurrentLevel <= 0)
    return;

  OCCT_ADD_MESSAGE_LEVEL_SENTRY ("levelAlert")

  Message_Messenger::StreamBuffer sout = Message::SendInfo();
  sout << "Level: " << theCurrentLevel << "(Single, no alerts on the level)" << std::endl;

  levelAlerts (theCurrentLevel + 1, theTopLevel);
}

// =======================================================================
// function : OnTestReportTree
// purpose :
// =======================================================================
void MessageView_ActionsTest::OnTestReportTree()
{
  OCCT_ADD_MESSAGE_LEVEL_SENTRY ("MessageModel_Actions::OnTestReportTree()")
  Message_Messenger::StreamBuffer sout = Message::SendInfo();

  int aTopLevel = 3;
  levelAlerts (1, aTopLevel);

  sout << "Alert: " << 4 << std::endl;
  levelAlert (1, aTopLevel);

  myTreeModel->UpdateTreeModel();
}