<commit_before>#include "HistoryScene.h"
#include "Record.h"

#pragma execution_character_set("utf-8")

USING_NS_CC;

static std::vector<Record> g_records;

Scene *HistoryScene::createScene(const std::function<void (const Record &)> &viewCallback) {
    auto scene = Scene::create();
    auto layer = HistoryScene::create();
    layer->_viewCallback = viewCallback;
    scene->addChild(layer);
    return scene;
}

static void lazyLoadRecords() {
    if (!g_records.empty()) {
        return;
    }

    std::string fileName = FileUtils::getInstance()->getWritablePath();
    fileName.append("history_record.json");
    std::string str = FileUtils::getInstance()->getStringFromFile(fileName);

    try {
        jw::cppJSON json;
        json.Parse(str.c_str());

        g_records.clear();
        g_records.reserve(json.size());
        std::transform(json.begin(), json.end(), std::back_inserter(g_records), [](const jw::cppJSON &json) {
            Record record;
            fromJson(&record, json);
            return record;
        });
    }
    catch (std::exception &e) {
        CCLOG("%s %s", __FUNCTION__, e.what());
    }
}

static void saveRecords() {
    std::string fileName = FileUtils::getInstance()->getWritablePath();
    fileName.append("history_record.json");
    FILE *file = fopen(fileName.c_str(), "wb");
    if (file != nullptr) {
        try {
            jw::cppJSON json(jw::cppJSON::ValueType::Array);
            std::transform(g_records.begin(), g_records.end(), std::back_inserter(json), [](const Record &record) {
                jw::cppJSON json(jw::cppJSON::ValueType::Object);
                toJson(record, &json);
                return json;
            });
            std::string str = json.stringfiy();
            fwrite(str.c_str(), 1, str.length(), file);
        }
        catch (std::exception &e) {
            CCLOG("%s %s", __FUNCTION__, e.what());
        }
        fclose(file);
    }
}

ui::Widget *HistoryScene::createRecordWidget(size_t idx, float width) {
    ui::Widget *widget = ui::Widget::create();
    widget->setContentSize(Size(width, 36.0f));

    ui::Button *button = ui::Button::create("source_material/btn_square_normal.png", "source_material/btn_square_highlighted.png");
    button->setScale9Enabled(true);
    button->setContentSize(Size(40.0f, 20.0f));
    button->setTitleColor(Color3B::BLACK);
    button->setTitleFontSize(12);
    button->setTitleText("删除");
    button->addClickEventListener([idx](Ref *) {
    });
    widget->addChild(button);
    button->setPosition(Vec2(width - 22.0f, 18.0f));

    button = ui::Button::create("source_material/btn_square_normal.png", "source_material/btn_square_highlighted.png");
    button->setScale9Enabled(true);
    button->setContentSize(Size(40.0f, 20.0f));
    button->setTitleColor(Color3B::BLACK);
    button->setTitleFontSize(12);
    button->setTitleText("查看");
    button->addClickEventListener([this, idx](Ref *) {
        _viewCallback(g_records[idx]);
        Director::getInstance()->popScene();
    });
    widget->addChild(button);
    button->setPosition(Vec2(width - 66.0f, 18.0f));

    const Record &record = g_records[idx];
    int scores[4] = { 0 };
    for (int i = 0; i < 16; ++i) {
        scores[0] += record.scores[i][0];
        scores[1] += record.scores[i][1];
        scores[2] += record.scores[i][2];
        scores[3] += record.scores[i][3];
    }

    char str[255];
    size_t len = 0;
    len += strftime(str, sizeof(str), "%Y-%m-%d %H:%M", localtime(&record.startTime));
    strcpy(str + len, " -- ");
    len += 4;
    len += strftime(str + len, sizeof(str) - len, "%Y-%m-%d %H:%M", localtime(&record.endTime));

    snprintf(str + len, sizeof(str) - len, "\n[%s(%+d) %s(%+d) %s(%+d) %s(%+d)]",
        record.name[0], scores[0], record.name[1], scores[1], record.name[2], scores[2], record.name[3], scores[3]);
    Label *label = Label::createWithSystemFont(str, "Arail", 10);
    widget->addChild(label);
    label->setPosition(Vec2((width - 88.0f) * 0.5f, 18.0f));

    return widget;
}

bool HistoryScene::init() {
    if (!BaseLayer::initWithTitle("历史记录")) {
        return false;
    }

    lazyLoadRecords();

    Size visibleSize = Director::getInstance()->getVisibleSize();
    Vec2 origin = Director::getInstance()->getVisibleOrigin();

    ui::Widget *innerNode = ui::Widget::create();
    innerNode->setAnchorPoint(Vec2::ANCHOR_BOTTOM_LEFT);
    const float scrollHeight = visibleSize.height - 35;
    const float innerNodeHeight = std::max<float>(g_records.size() * 40, scrollHeight);
    innerNode->setContentSize(Size(visibleSize.width, innerNodeHeight));

    float y = innerNodeHeight - 20;
    for (std::vector<Record>::size_type i = 0; i < g_records.size(); ++i) {
        ui::Widget *widget = createRecordWidget(i, visibleSize.width);
        innerNode->addChild(widget);
        widget->setPosition(Vec2(visibleSize.width * 0.5f, y));
        y -= 40;
    }

    ui::ScrollView *scrollView = ui::ScrollView::create();
    scrollView->setDirection(ui::ScrollView::Direction::VERTICAL);
    scrollView->setContentSize(Size(visibleSize.width, scrollHeight));
    scrollView->setScrollBarPositionFromCorner(Vec2(10, 10));
    scrollView->setInnerContainerSize(innerNode->getContentSize());
    scrollView->setAnchorPoint(Vec2::ANCHOR_MIDDLE);
    scrollView->setPosition(Vec2(origin.x + visibleSize.width * 0.5f, origin.y + visibleSize.height * 0.5f - 15.0f));
    this->addChild(scrollView);

    scrollView->addChild(innerNode);

    return true;
}

void HistoryScene::addRecord(const Record &record) {
    lazyLoadRecords();
    if (g_records.end() == std::find(g_records.begin(), g_records.end(), record)) {
        g_records.push_back(record);
        saveRecords();
    }
}
<commit_msg>先将就这样子删除历史记录吧<commit_after>#include "HistoryScene.h"
#include "Record.h"
#include "../widget/AlertLayer.h"

#pragma execution_character_set("utf-8")

USING_NS_CC;

static std::vector<Record> g_records;

Scene *HistoryScene::createScene(const std::function<void (const Record &)> &viewCallback) {
    auto scene = Scene::create();
    auto layer = HistoryScene::create();
    layer->_viewCallback = viewCallback;
    scene->addChild(layer);
    return scene;
}

static void lazyLoadRecords() {
    if (!g_records.empty()) {
        return;
    }

    std::string fileName = FileUtils::getInstance()->getWritablePath();
    fileName.append("history_record.json");
    std::string str = FileUtils::getInstance()->getStringFromFile(fileName);

    try {
        jw::cppJSON json;
        json.Parse(str.c_str());

        g_records.clear();
        g_records.reserve(json.size());
        std::transform(json.begin(), json.end(), std::back_inserter(g_records), [](const jw::cppJSON &json) {
            Record record;
            fromJson(&record, json);
            return record;
        });
    }
    catch (std::exception &e) {
        CCLOG("%s %s", __FUNCTION__, e.what());
    }
}

static void saveRecords() {
    std::string fileName = FileUtils::getInstance()->getWritablePath();
    fileName.append("history_record.json");
    FILE *file = fopen(fileName.c_str(), "wb");
    if (file != nullptr) {
        try {
            jw::cppJSON json(jw::cppJSON::ValueType::Array);
            std::transform(g_records.begin(), g_records.end(), std::back_inserter(json), [](const Record &record) {
                jw::cppJSON json(jw::cppJSON::ValueType::Object);
                toJson(record, &json);
                return json;
            });
            std::string str = json.stringfiy();
            fwrite(str.c_str(), 1, str.length(), file);
        }
        catch (std::exception &e) {
            CCLOG("%s %s", __FUNCTION__, e.what());
        }
        fclose(file);
    }
}

ui::Widget *HistoryScene::createRecordWidget(size_t idx, float width) {
    ui::Widget *widget = ui::Widget::create();
    widget->setContentSize(Size(width, 36.0f));

    ui::Button *button = ui::Button::create("source_material/btn_square_normal.png", "source_material/btn_square_highlighted.png");
    button->setScale9Enabled(true);
    button->setContentSize(Size(40.0f, 20.0f));
    button->setTitleColor(Color3B::BLACK);
    button->setTitleFontSize(12);
    button->setTitleText("删除");
    button->addClickEventListener([this, idx](Ref *) {
        AlertLayer::showWithMessage("删除记录", "删除后无法找回，确认删除？", [this, idx]() {
            g_records.erase(g_records.begin() + idx);
            saveRecords();
            std::function<void (const Record &)> viewCallback = std::move(_viewCallback);
            Director::getInstance()->popScene();
            Director::getInstance()->pushScene(HistoryScene::createScene(viewCallback));
        }, nullptr);
    });
    widget->addChild(button);
    button->setPosition(Vec2(width - 22.0f, 18.0f));

    button = ui::Button::create("source_material/btn_square_normal.png", "source_material/btn_square_highlighted.png");
    button->setScale9Enabled(true);
    button->setContentSize(Size(40.0f, 20.0f));
    button->setTitleColor(Color3B::BLACK);
    button->setTitleFontSize(12);
    button->setTitleText("查看");
    button->addClickEventListener([this, idx](Ref *) {
        _viewCallback(g_records[idx]);
        Director::getInstance()->popScene();
    });
    widget->addChild(button);
    button->setPosition(Vec2(width - 66.0f, 18.0f));

    const Record &record = g_records[idx];
    int scores[4] = { 0 };
    for (int i = 0; i < 16; ++i) {
        scores[0] += record.scores[i][0];
        scores[1] += record.scores[i][1];
        scores[2] += record.scores[i][2];
        scores[3] += record.scores[i][3];
    }

    char str[255];
    size_t len = 0;
    len += strftime(str, sizeof(str), "%Y-%m-%d %H:%M", localtime(&record.startTime));
    strcpy(str + len, " -- ");
    len += 4;
    len += strftime(str + len, sizeof(str) - len, "%Y-%m-%d %H:%M", localtime(&record.endTime));

    snprintf(str + len, sizeof(str) - len, "\n[%s(%+d) %s(%+d) %s(%+d) %s(%+d)]",
        record.name[0], scores[0], record.name[1], scores[1], record.name[2], scores[2], record.name[3], scores[3]);
    Label *label = Label::createWithSystemFont(str, "Arail", 10);
    widget->addChild(label);
    label->setPosition(Vec2((width - 88.0f) * 0.5f, 18.0f));

    return widget;
}

bool HistoryScene::init() {
    if (!BaseLayer::initWithTitle("历史记录")) {
        return false;
    }

    lazyLoadRecords();

    Size visibleSize = Director::getInstance()->getVisibleSize();
    Vec2 origin = Director::getInstance()->getVisibleOrigin();

    ui::Widget *innerNode = ui::Widget::create();
    innerNode->setAnchorPoint(Vec2::ANCHOR_BOTTOM_LEFT);
    const float scrollHeight = visibleSize.height - 35;
    const float innerNodeHeight = std::max<float>(g_records.size() * 40, scrollHeight);
    innerNode->setContentSize(Size(visibleSize.width, innerNodeHeight));

    float y = innerNodeHeight - 20;
    for (std::vector<Record>::size_type i = 0; i < g_records.size(); ++i) {
        ui::Widget *widget = createRecordWidget(i, visibleSize.width);
        innerNode->addChild(widget);
        widget->setPosition(Vec2(visibleSize.width * 0.5f, y));
        y -= 40;
    }

    ui::ScrollView *scrollView = ui::ScrollView::create();
    scrollView->setDirection(ui::ScrollView::Direction::VERTICAL);
    scrollView->setContentSize(Size(visibleSize.width, scrollHeight));
    scrollView->setScrollBarPositionFromCorner(Vec2(10, 10));
    scrollView->setInnerContainerSize(innerNode->getContentSize());
    scrollView->setAnchorPoint(Vec2::ANCHOR_MIDDLE);
    scrollView->setPosition(Vec2(origin.x + visibleSize.width * 0.5f, origin.y + visibleSize.height * 0.5f - 15.0f));
    this->addChild(scrollView);

    scrollView->addChild(innerNode);

    return true;
}

void HistoryScene::addRecord(const Record &record) {
    lazyLoadRecords();
    if (g_records.end() == std::find(g_records.begin(), g_records.end(), record)) {
        g_records.push_back(record);
        saveRecords();
    }
}
<|endoftext|>


<commit_before>/*=========================================================================

  Program:   Monteverdi2
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) Centre National d'Etudes Spatiales. All rights reserved .
  See OTBCopyright.txt for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

#include "mvdApplication.h"

//
// System includes (sorted by alphabetic order)
#include <iostream>

//
// Qt includes (sorted by alphabetic order)
#include <QApplication>
#include <QDir>
#include <QLibraryInfo>
#include <QLocale>
#include <QMessageBox>
#include <QTextCodec>
#include <QTranslator>

//
// OTB includes (sorted by alphabetic order)

//
// Monteverdi includes (sorted by alphabetic order)
#include "ConfigureMonteverdi2.h"

//
// Class implementation.
namespace mvd
{
/*
  TRANSLATOR mvd::Application

  Necessary for lupdate to be aware of C++ namespaces.

  Context comment for translator.
*/

/*******************************************************************************/
Application
::Application( int& argc, char** argv ) :
  QApplication( argc, argv ),
  m_IsRunningFromBuildDir( false )
{
  InitializeCore();

  InitializeLocale();

  QObject::connect(
    this, SIGNAL( aboutToQuit() ),
    this, SLOT( OnAboutToQuit() )
    );
}

/*******************************************************************************/
Application
::~Application()
{
}

/*******************************************************************************/
void
Application
::InitializeCore()
{
  //
  //
#if 1
  QTextCodec::setCodecForTr( QTextCodec::codecForName( "utf8" ) );
#endif

  //
  // Setup application tags.
  QCoreApplication::setApplicationName(
    PROJECT_NAME
  );
  QCoreApplication::setApplicationVersion(
    Monteverdi2_VERSION_STRING
  );

  //
  // Setup organization tags.
  QCoreApplication::setOrganizationName(
    tr( "Centre National d'Etudes Spatiales (CNES)" )
  );
  QCoreApplication::setOrganizationDomain(
    "orfeo-toolbox.org"
  );
}

/*******************************************************************************/
void
Application
::InitializeDataDir()
{
}

/*******************************************************************************/
void
Application
::InitializeLocale()
{
  //
  // 1. default UI language is english (no translation).
  QLocale sys_lc( QLocale::system() );
  if( sys_lc.language()==QLocale::C ||
      ( sys_lc.language()==QLocale::English &&
	sys_lc.country()==QLocale::UnitedStates ) )
    {
    return;
    }

  /*
  QLocale ui_lc(
#if 1
    QLocale::English, QLocale::UnitedStates
#else
    QLocale::C, QLocale::AnyCountry
#endif
  );

  if( sys_lc.language()==ui_lc.language()
      && sys_lc.country()==ui_lc.country()
#if QT_VERSION>=0x040800
      && sys_lc.script()==ui_lc.script()
#endif
  )
    {
    return;
    }
  */

  //
  // 2. Choose i18n path between build dir and install dir.
  QDir i18n_dir;
  QDir bin_dir( QDir::cleanPath( QCoreApplication::applicationDirPath() ) );
  QDir build_i18n_dir( bin_dir );

  // If build dir is identified...
  if( build_i18n_dir.cd( "../i18n" ) &&
      build_i18n_dir.exists( "../" Monteverdi2_CONFIGURE_FILE ) )
    {
    m_IsRunningFromBuildDir = true;

    // ...use build dir as prioritary load path for translation.
    i18n_dir = build_i18n_dir;

    // TODO: Use log system to trace message.
    qDebug()
      << tr( "Running from build directory '%1'." ).arg( bin_dir.path() );
    }
  // Otherwise...
  else
    {
    m_IsRunningFromBuildDir = false;

    QDir install_i18n_dir( QDir::cleanPath( Monteverdi2_INSTALL_DATA_I18N_DIR ) );
    // ...if install data dir is identified
    if( install_i18n_dir.exists() )
      {
      // ...use install data dir as load path for translation.
      i18n_dir = install_i18n_dir;

      // TODO: Use log system to trace message.
      qDebug()
	<< tr( "Running from install directory '%1'." ).arg( Monteverdi2_INSTALL_BIN_DIR );
      }
    // Otherwise
    else
      {
      QString message(
	tr( "Failed to access translation-files directory '%1'." )
	.arg( install_i18n_dir.path() )
      );

      // TODO: Use log system to trace error while loading locale translation file.

      qDebug() << message;

      // TODO: morph into better HMI design.
      QMessageBox::critical( NULL, tr( "Critical error!" ), message );

      return;
      }
    }

  //
  // 3.1 Stack Qt translator.
  LoadAndInstallTranslator(
    "qt_" + sys_lc.name(),
    QLibraryInfo::location( QLibraryInfo::TranslationsPath  )
  );

  //
  // 3.2 Stack Monteverdi2 translator as prioritary over Qt translator.
  LoadAndInstallTranslator( sys_lc.name(), i18n_dir.path() );

  // TODO: Record locale translation filename(s) used in UI component (e.g.
  // AboutDialog, Settings dialog, Information dialog etc.)
}

/*******************************************************************************/
bool
Application
::LoadAndInstallTranslator(const QString& filename,
			   const QString& directory,
			   const QString& searchDelimiters,
			   const QString& suffix )
{
  QString filename_ext(
    filename +
    ( suffix.isNull()
	? ".qm"
	: suffix )
  );

  // (a) Do need to new QTranslator() here!
  QTranslator* lc_translator = new QTranslator( this );

  if( !lc_translator->load( filename, directory, searchDelimiters, suffix ) )
    {
    QString message(
      tr( "Failed to load '%1' translation file from '%2'." )
      .arg( filename_ext )
      .arg( directory )
    );

    // TODO: Use log system to trace error while loading locale translation file.

    qWarning() << message;

    // TODO: morph into better HMI design.
    QMessageBox::warning( NULL, tr( "Warning!" ), message );

    return false;
    }

  // (a) ...because QTranslator needs to be alive during the whole
  // lifespan of the application.
  QCoreApplication::installTranslator( lc_translator );

  QString message(
    tr( "Successfully loaded '%1' translation file from '%2'." )
    .arg( filename_ext )
    .arg( directory )
  );

  // TODO: Log locale translation filename used.

  qDebug() << message;

  return true;
}

/*******************************************************************************/
/* SLOTS                                                                       */
/*******************************************************************************/
void
Application
::OnAboutToQuit()
{
  qDebug() << tr( ">DEBUG> mvd::Application::OnAboutToQuit()." );
}

} // end namespace 'mvd'
<commit_msg>STYLE: Comment cleanup.<commit_after>/*=========================================================================

  Program:   Monteverdi2
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) Centre National d'Etudes Spatiales. All rights reserved .
  See OTBCopyright.txt for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

#include "mvdApplication.h"

//
// System includes (sorted by alphabetic order)
#include <iostream>

//
// Qt includes (sorted by alphabetic order)
#include <QApplication>
#include <QDir>
#include <QLibraryInfo>
#include <QLocale>
#include <QMessageBox>
#include <QTextCodec>
#include <QTranslator>

//
// OTB includes (sorted by alphabetic order)

//
// Monteverdi includes (sorted by alphabetic order)
#include "ConfigureMonteverdi2.h"

//
// Class implementation.
namespace mvd
{
/*
  TRANSLATOR mvd::Application

  Necessary for lupdate to be aware of C++ namespaces.

  Context comment for translator.
*/

/*******************************************************************************/
Application
::Application( int& argc, char** argv ) :
  QApplication( argc, argv ),
  m_IsRunningFromBuildDir( false )
{
  InitializeCore();

  InitializeLocale();

  QObject::connect(
    this, SIGNAL( aboutToQuit() ),
    this, SLOT( OnAboutToQuit() )
    );
}

/*******************************************************************************/
Application
::~Application()
{
}

/*******************************************************************************/
void
Application
::InitializeCore()
{
  //
  //
#if 1
  QTextCodec::setCodecForTr( QTextCodec::codecForName( "utf8" ) );
#endif

  //
  // Setup application tags.
  QCoreApplication::setApplicationName(
    PROJECT_NAME
  );
  QCoreApplication::setApplicationVersion(
    Monteverdi2_VERSION_STRING
  );

  //
  // Setup organization tags.
  QCoreApplication::setOrganizationName(
    tr( "Centre National d'Etudes Spatiales (CNES)" )
  );
  QCoreApplication::setOrganizationDomain(
    "orfeo-toolbox.org"
  );
}

/*******************************************************************************/
void
Application
::InitializeDataDir()
{
}

/*******************************************************************************/
void
Application
::InitializeLocale()
{
  //
  // 1. default UI language is english (no translation).
  QLocale sys_lc( QLocale::system() );
  if( sys_lc.language()==QLocale::C ||
      ( sys_lc.language()==QLocale::English &&
	sys_lc.country()==QLocale::UnitedStates ) )
    {
    return;
    }

  //
  // 2. Choose i18n path between build dir and install dir.
  QDir i18n_dir;
  QDir bin_dir( QDir::cleanPath( QCoreApplication::applicationDirPath() ) );
  QDir build_i18n_dir( bin_dir );

  // If build dir is identified...
  if( build_i18n_dir.cd( "../i18n" ) &&
      build_i18n_dir.exists( "../" Monteverdi2_CONFIGURE_FILE ) )
    {
    m_IsRunningFromBuildDir = true;

    // ...use build dir as prioritary load path for translation.
    i18n_dir = build_i18n_dir;

    // TODO: Use log system to trace message.
    qDebug()
      << tr( "Running from build directory '%1'." ).arg( bin_dir.path() );
    }
  // Otherwise...
  else
    {
    m_IsRunningFromBuildDir = false;

    QDir install_i18n_dir( QDir::cleanPath( Monteverdi2_INSTALL_DATA_I18N_DIR ) );
    // ...if install data dir is identified
    if( install_i18n_dir.exists() )
      {
      // ...use install data dir as load path for translation.
      i18n_dir = install_i18n_dir;

      // TODO: Use log system to trace message.
      qDebug()
	<< tr( "Running from install directory '%1'." ).arg( Monteverdi2_INSTALL_BIN_DIR );
      }
    // Otherwise
    else
      {
      QString message(
	tr( "Failed to access translation-files directory '%1'." )
	.arg( install_i18n_dir.path() )
      );

      // TODO: Use log system to trace error while loading locale translation file.

      qDebug() << message;

      // TODO: morph into better HMI design.
      QMessageBox::critical( NULL, tr( "Critical error!" ), message );

      return;
      }
    }

  //
  // 3.1 Stack Qt translator.
  LoadAndInstallTranslator(
    "qt_" + sys_lc.name(),
    QLibraryInfo::location( QLibraryInfo::TranslationsPath  )
  );

  //
  // 3.2 Stack Monteverdi2 translator as prioritary over Qt translator.
  LoadAndInstallTranslator( sys_lc.name(), i18n_dir.path() );

  // TODO: Record locale translation filename(s) used in UI component (e.g.
  // AboutDialog, Settings dialog, Information dialog etc.)
}

/*******************************************************************************/
bool
Application
::LoadAndInstallTranslator(const QString& filename,
			   const QString& directory,
			   const QString& searchDelimiters,
			   const QString& suffix )
{
  QString filename_ext(
    filename +
    ( suffix.isNull()
	? ".qm"
	: suffix )
  );

  // (a) Do need to new QTranslator() here!
  QTranslator* lc_translator = new QTranslator( this );

  if( !lc_translator->load( filename, directory, searchDelimiters, suffix ) )
    {
    QString message(
      tr( "Failed to load '%1' translation file from '%2'." )
      .arg( filename_ext )
      .arg( directory )
    );

    // TODO: Use log system to trace error while loading locale translation file.

    qWarning() << message;

    // TODO: morph into better HMI design.
    QMessageBox::warning( NULL, tr( "Warning!" ), message );

    return false;
    }

  // (a) ...because QTranslator needs to be alive during the whole
  // lifespan of the application.
  QCoreApplication::installTranslator( lc_translator );

  QString message(
    tr( "Successfully loaded '%1' translation file from '%2'." )
    .arg( filename_ext )
    .arg( directory )
  );

  // TODO: Log locale translation filename used.

  qDebug() << message;

  return true;
}

/*******************************************************************************/
/* SLOTS                                                                       */
/*******************************************************************************/
void
Application
::OnAboutToQuit()
{
  qDebug() << tr( ">DEBUG> mvd::Application::OnAboutToQuit()." );
}

} // end namespace 'mvd'
<|endoftext|>


<commit_before>// $Id$
//
//  Copyright (C) 2003-2006 Rational Discovery LLC
//
//   @@ All Rights Reserved @@
//  This file is part of the RDKit.
//  The contents are covered by the terms of the BSD license
//  which is included in the file license.txt, found at the root
//  of the RDKit source tree.
//
#include <GraphMol/RDKitBase.h>
#include <GraphMol/RDKitQueries.h>
#include <RDGeneral/RDLog.h>
#include <GraphMol/SmilesParse/SmilesParse.h>
#include <GraphMol/SmilesParse/SmilesWrite.h>

#include "FragCatGenerator.h"

#include "FragCatalogEntry.h"
#include "FragCatParams.h"
#include "FragCatalogUtils.h"
#include "FragFPGenerator.h"
#include <stdlib.h>
#include <iostream>
#include <fstream>

#include <GraphMol/Subgraphs/SubgraphUtils.h>
#include <GraphMol/Subgraphs/Subgraphs.h>
#include <GraphMol/FileParsers/MolSupplier.h>
#include <RDGeneral/types.h>
#include <RDGeneral/FileParseException.h>
#include <DataStructs/BitVects.h>

using namespace RDKit;

void testMols(std::vector<ROMol *> &mols,FragFPGenerator &fpGen,FragCatalog &fcat){
  std::vector<ROMol *>::iterator mi;
  int nDone=0;
  for (mi = mols.begin(); mi != mols.end(); mi++) {
    ExplicitBitVect *fp = fpGen.getFPForMol(*(*mi), fcat);
    switch(nDone){
    case 0:
      TEST_ASSERT(fp->getNumOnBits()==3);
      TEST_ASSERT((*fp)[0]);
      TEST_ASSERT((*fp)[1]);
      TEST_ASSERT((*fp)[2]);
      break;
    case 1:
      TEST_ASSERT(fp->getNumOnBits()==2);
      TEST_ASSERT((*fp)[1]);
      TEST_ASSERT((*fp)[3]);
      break;
    case 2:
      TEST_ASSERT(fp->getNumOnBits()==3);
      TEST_ASSERT((*fp)[1]);
      TEST_ASSERT((*fp)[4]);
      TEST_ASSERT((*fp)[5]);
      break;
    case 3:
      TEST_ASSERT(fp->getNumOnBits()==3);
      TEST_ASSERT((*fp)[1]);
      TEST_ASSERT((*fp)[6]);
      TEST_ASSERT((*fp)[7]);
      break;
    case 4:
      TEST_ASSERT(fp->getNumOnBits()==2);
      TEST_ASSERT((*fp)[0]);
      TEST_ASSERT((*fp)[8]);
      break;
    case 5:
      TEST_ASSERT(fp->getNumOnBits()==3);
      TEST_ASSERT((*fp)[0]);
      TEST_ASSERT((*fp)[6]);
      TEST_ASSERT((*fp)[9]);
      break;
    case 6:
      TEST_ASSERT(fp->getNumOnBits()==5);
      TEST_ASSERT((*fp)[0]);
      TEST_ASSERT((*fp)[1]);
      TEST_ASSERT((*fp)[2]);
      TEST_ASSERT((*fp)[3]);
      TEST_ASSERT((*fp)[10]);
      break;
    }
    nDone += 1;
  }
}

void test1(){
  std::string rdbase = getenv("RDBASE");
  std::string fname = rdbase + "/Code/GraphMol/FragCatalog/test_data/mols.smi";
  std::string fgrpFile = rdbase + "/Code/GraphMol/FragCatalog/test_data/funcGroups.txt";
  SmilesMolSupplier suppl(fname," ",0,1,false);

  FragCatParams *fparams = new FragCatParams(1, 6, fgrpFile, 1.0e-8);
  TEST_ASSERT(fparams->getNumFuncGroups()==15);
  FragCatalog fcat(fparams);
  FragCatGenerator catGen;

  std::vector<ROMol *> mols;
  unsigned int nDone=0;
  ROMol *m = suppl.next();
  while (m) {
    mols.push_back(m);
    nDone+=1;
    catGen.addFragsFromMol(*m, &fcat);
    try{
      m = suppl.next();
    } catch( FileParseException &) {
      m = NULL;
    }
  }
  TEST_ASSERT(mols.size()==16);
  TEST_ASSERT(nDone==16);
  int nents = fcat.getNumEntries();
  std::cerr<<" "<<nents<<std::endl;
  TEST_ASSERT(nents==21);
  FragFPGenerator fpGen;

  BOOST_LOG(rdInfoLog) << "----- Test 1" << std::endl;
  testMols(mols,fpGen,fcat);
  BOOST_LOG(rdInfoLog) << "---- Done" << std::endl;

  //----------------------------------------------------------
  //  SERIALIZATION TESTS
  //----------------------------------------------------------

  // make sure we can pickle and unpickle parameter objects:
  FragCatParams newParams;
  std::string pickle=fparams->Serialize();
  newParams.initFromString(pickle);
  TEST_ASSERT(newParams.getLowerFragLength()==fparams->getLowerFragLength());
  TEST_ASSERT(newParams.getUpperFragLength()==fparams->getUpperFragLength());
  TEST_ASSERT(newParams.getTolerance()==fparams->getTolerance());
  TEST_ASSERT(newParams.getNumFuncGroups()==fparams->getNumFuncGroups());

  // make sure we can pickle and unpickle catalog entries:
  const FragCatalogEntry *fpEntry=fcat.getEntryWithIdx(0);
  FragCatalogEntry *fpEntry2 = new FragCatalogEntry();
  fpEntry2->initFromString(fpEntry->Serialize());
  TEST_ASSERT(fpEntry->getDescription()==fpEntry2->getDescription());
  TEST_ASSERT(fpEntry->getOrder()==fpEntry2->getOrder());
  TEST_ASSERT(fpEntry->getBitId()==fpEntry2->getBitId());
  TEST_ASSERT(fpEntry2->match(fpEntry,1e-8));
  TEST_ASSERT(fpEntry->match(fpEntry2,1e-8));

  // test catalogs' initFromString:
  FragCatalog fcat2;
  fcat2.initFromString(fcat.Serialize());
  TEST_ASSERT(fcat2.getNumEntries()==fcat.getNumEntries());
  BOOST_LOG(rdInfoLog) << "----- Test 2" << std::endl;
  testMols(mols,fpGen,fcat2);
  BOOST_LOG(rdInfoLog) << "---- Done" << std::endl;

  // and the pickle ctor:
  FragCatalog *fcat3 = new FragCatalog(fcat.Serialize());
  TEST_ASSERT(fcat3->getNumEntries()==fcat.getNumEntries());
  BOOST_LOG(rdInfoLog) << "----- Test 3" << std::endl;
  testMols(mols,fpGen,*fcat3);
  BOOST_LOG(rdInfoLog) << "---- Done" << std::endl;

  //----------------------------------------------------------
  // test issue 115
  //----------------------------------------------------------
  BOOST_LOG(rdInfoLog) << "----- Test Issue 115" << std::endl;
  delete fparams;
  fparams = new FragCatParams(3, 3, fgrpFile, 1.0e-8);
  TEST_ASSERT(fparams->getNumFuncGroups()==15);
  delete fcat3;
  fcat3 = new FragCatalog(fparams);
  suppl.reset();
  nDone=0;
  while (!suppl.atEnd()){
    nDone++;
    ROMol *m = suppl.next();
    catGen.addFragsFromMol(*m, fcat3);
    delete m;
  }
  TEST_ASSERT(nDone==suppl.length());
  TEST_ASSERT(fcat3->getNumEntries()==21);
  TEST_ASSERT(fcat3->getFPLength()==10);
  for(unsigned int i=0;i<fcat3->getFPLength();i++){
    TEST_ASSERT(fcat3->getEntryWithBitId(i)->getOrder()==3);
  }
  BOOST_LOG(rdInfoLog) << "---- Done" << std::endl;

  //----------------------------------------------------------
  // test issue 117
  //----------------------------------------------------------
  BOOST_LOG(rdInfoLog) << "----- Test Issue 117" << std::endl;
  delete fparams;
  fparams = new FragCatParams(1, 2, fgrpFile, 1.0e-8);
  delete fcat3;
  fcat3 = new FragCatalog(fparams);
  ROMol *tmpMol=SmilesToMol("OC(N)CO");
  TEST_ASSERT(tmpMol);
  catGen.addFragsFromMol(*tmpMol, fcat3);
  TEST_ASSERT(fcat3->getNumEntries()==1);
  std::cout << fcat3->getEntryWithBitId(0)->getDescription() << std::endl;
  TEST_ASSERT(fcat3->getEntryWithBitId(0)->getDescription()=="C<-O>C(<-O>)<-N>");
  BOOST_LOG(rdInfoLog) << "---- Done" << std::endl;

  delete tmpMol;
}

void testIssue294(){
  BOOST_LOG(rdInfoLog) << "---- Test Issue294\n  Watch memory usage." << std::endl;
  std::string rdbase = getenv("RDBASE");
  std::string fname = rdbase + "/Code/GraphMol/FragCatalog/test_data/mols.smi";
  std::string fgrpFile = rdbase + "/Code/GraphMol/FragCatalog/test_data/funcGroups.txt";
  SmilesMolSupplier suppl(fname," ",0,1,false);

  FragCatParams *fparams = new FragCatParams(1, 6, fgrpFile, 1.0e-8);
  FragCatalog fcat(fparams);
  FragCatGenerator catGen;

  std::vector<ROMol *> mols;
  ROMol *m = suppl.next();
  while (m) {
    mols.push_back(m);
    catGen.addFragsFromMol(*m, &fcat);
    try{
      m = suppl.next();
    } catch( FileParseException &) {
      m = NULL;
    }
  }
  int nents = fcat.getNumEntries();
  TEST_ASSERT(nents==21);
  FragFPGenerator fpGen;

  m = mols[0];

  for(unsigned int i=0;i<200;i++){
    for (std::vector<ROMol *>::const_iterator mi = mols.begin();
	 mi != mols.end(); mi++) {
      ExplicitBitVect *fp = fpGen.getFPForMol(*(*mi), fcat);
      delete fp;
    }
  }
  BOOST_LOG(rdInfoLog) << "---- Done" << std::endl;
}

int main() {
  RDLog::InitLogs();
  test1();
  testIssue294();
  return 0;

}

<commit_msg>turn off debug printing<commit_after>// $Id$
//
//  Copyright (C) 2003-2006 Rational Discovery LLC
//
//   @@ All Rights Reserved @@
//  This file is part of the RDKit.
//  The contents are covered by the terms of the BSD license
//  which is included in the file license.txt, found at the root
//  of the RDKit source tree.
//
#include <GraphMol/RDKitBase.h>
#include <GraphMol/RDKitQueries.h>
#include <RDGeneral/RDLog.h>
#include <GraphMol/SmilesParse/SmilesParse.h>
#include <GraphMol/SmilesParse/SmilesWrite.h>

#include "FragCatGenerator.h"

#include "FragCatalogEntry.h"
#include "FragCatParams.h"
#include "FragCatalogUtils.h"
#include "FragFPGenerator.h"
#include <stdlib.h>
#include <iostream>
#include <fstream>

#include <GraphMol/Subgraphs/SubgraphUtils.h>
#include <GraphMol/Subgraphs/Subgraphs.h>
#include <GraphMol/FileParsers/MolSupplier.h>
#include <RDGeneral/types.h>
#include <RDGeneral/FileParseException.h>
#include <DataStructs/BitVects.h>

using namespace RDKit;

void testMols(std::vector<ROMol *> &mols,FragFPGenerator &fpGen,FragCatalog &fcat){
  std::vector<ROMol *>::iterator mi;
  int nDone=0;
  for (mi = mols.begin(); mi != mols.end(); mi++) {
    ExplicitBitVect *fp = fpGen.getFPForMol(*(*mi), fcat);
    switch(nDone){
    case 0:
      TEST_ASSERT(fp->getNumOnBits()==3);
      TEST_ASSERT((*fp)[0]);
      TEST_ASSERT((*fp)[1]);
      TEST_ASSERT((*fp)[2]);
      break;
    case 1:
      TEST_ASSERT(fp->getNumOnBits()==2);
      TEST_ASSERT((*fp)[1]);
      TEST_ASSERT((*fp)[3]);
      break;
    case 2:
      TEST_ASSERT(fp->getNumOnBits()==3);
      TEST_ASSERT((*fp)[1]);
      TEST_ASSERT((*fp)[4]);
      TEST_ASSERT((*fp)[5]);
      break;
    case 3:
      TEST_ASSERT(fp->getNumOnBits()==3);
      TEST_ASSERT((*fp)[1]);
      TEST_ASSERT((*fp)[6]);
      TEST_ASSERT((*fp)[7]);
      break;
    case 4:
      TEST_ASSERT(fp->getNumOnBits()==2);
      TEST_ASSERT((*fp)[0]);
      TEST_ASSERT((*fp)[8]);
      break;
    case 5:
      TEST_ASSERT(fp->getNumOnBits()==3);
      TEST_ASSERT((*fp)[0]);
      TEST_ASSERT((*fp)[6]);
      TEST_ASSERT((*fp)[9]);
      break;
    case 6:
      TEST_ASSERT(fp->getNumOnBits()==5);
      TEST_ASSERT((*fp)[0]);
      TEST_ASSERT((*fp)[1]);
      TEST_ASSERT((*fp)[2]);
      TEST_ASSERT((*fp)[3]);
      TEST_ASSERT((*fp)[10]);
      break;
    }
    nDone += 1;
  }
}

void test1(){
  std::string rdbase = getenv("RDBASE");
  std::string fname = rdbase + "/Code/GraphMol/FragCatalog/test_data/mols.smi";
  std::string fgrpFile = rdbase + "/Code/GraphMol/FragCatalog/test_data/funcGroups.txt";
  SmilesMolSupplier suppl(fname," ",0,1,false);

  FragCatParams *fparams = new FragCatParams(1, 6, fgrpFile, 1.0e-8);
  TEST_ASSERT(fparams->getNumFuncGroups()==15);
  FragCatalog fcat(fparams);
  FragCatGenerator catGen;

  std::vector<ROMol *> mols;
  unsigned int nDone=0;
  ROMol *m = suppl.next();
  while (m) {
    mols.push_back(m);
    nDone+=1;
    catGen.addFragsFromMol(*m, &fcat);
    try{
      m = suppl.next();
    } catch( FileParseException &) {
      m = NULL;
    }
  }
  TEST_ASSERT(mols.size()==16);
  TEST_ASSERT(nDone==16);
  int nents = fcat.getNumEntries();
  std::cerr<<" "<<nents<<std::endl;
  TEST_ASSERT(nents==21);
  FragFPGenerator fpGen;

  BOOST_LOG(rdInfoLog) << "----- Test 1" << std::endl;
  testMols(mols,fpGen,fcat);
  BOOST_LOG(rdInfoLog) << "---- Done" << std::endl;

  //----------------------------------------------------------
  //  SERIALIZATION TESTS
  //----------------------------------------------------------

  // make sure we can pickle and unpickle parameter objects:
  FragCatParams newParams;
  std::string pickle=fparams->Serialize();
  newParams.initFromString(pickle);
  TEST_ASSERT(newParams.getLowerFragLength()==fparams->getLowerFragLength());
  TEST_ASSERT(newParams.getUpperFragLength()==fparams->getUpperFragLength());
  TEST_ASSERT(newParams.getTolerance()==fparams->getTolerance());
  TEST_ASSERT(newParams.getNumFuncGroups()==fparams->getNumFuncGroups());

  // make sure we can pickle and unpickle catalog entries:
  const FragCatalogEntry *fpEntry=fcat.getEntryWithIdx(0);
  FragCatalogEntry *fpEntry2 = new FragCatalogEntry();
  fpEntry2->initFromString(fpEntry->Serialize());
  TEST_ASSERT(fpEntry->getDescription()==fpEntry2->getDescription());
  TEST_ASSERT(fpEntry->getOrder()==fpEntry2->getOrder());
  TEST_ASSERT(fpEntry->getBitId()==fpEntry2->getBitId());
  TEST_ASSERT(fpEntry2->match(fpEntry,1e-8));
  TEST_ASSERT(fpEntry->match(fpEntry2,1e-8));

  // test catalogs' initFromString:
  FragCatalog fcat2;
  fcat2.initFromString(fcat.Serialize());
  TEST_ASSERT(fcat2.getNumEntries()==fcat.getNumEntries());
  BOOST_LOG(rdInfoLog) << "----- Test 2" << std::endl;
  testMols(mols,fpGen,fcat2);
  BOOST_LOG(rdInfoLog) << "---- Done" << std::endl;

  // and the pickle ctor:
  FragCatalog *fcat3 = new FragCatalog(fcat.Serialize());
  TEST_ASSERT(fcat3->getNumEntries()==fcat.getNumEntries());
  BOOST_LOG(rdInfoLog) << "----- Test 3" << std::endl;
  testMols(mols,fpGen,*fcat3);
  BOOST_LOG(rdInfoLog) << "---- Done" << std::endl;

  //----------------------------------------------------------
  // test issue 115
  //----------------------------------------------------------
  BOOST_LOG(rdInfoLog) << "----- Test Issue 115" << std::endl;
  delete fparams;
  fparams = new FragCatParams(3, 3, fgrpFile, 1.0e-8);
  TEST_ASSERT(fparams->getNumFuncGroups()==15);
  delete fcat3;
  fcat3 = new FragCatalog(fparams);
  suppl.reset();
  nDone=0;
  while (!suppl.atEnd()){
    nDone++;
    ROMol *m = suppl.next();
    catGen.addFragsFromMol(*m, fcat3);
    delete m;
  }
  TEST_ASSERT(nDone==suppl.length());
  TEST_ASSERT(fcat3->getNumEntries()==21);
  TEST_ASSERT(fcat3->getFPLength()==10);
  for(unsigned int i=0;i<fcat3->getFPLength();i++){
    TEST_ASSERT(fcat3->getEntryWithBitId(i)->getOrder()==3);
  }
  BOOST_LOG(rdInfoLog) << "---- Done" << std::endl;

  //----------------------------------------------------------
  // test issue 117
  //----------------------------------------------------------
  BOOST_LOG(rdInfoLog) << "----- Test Issue 117" << std::endl;
  delete fparams;
  fparams = new FragCatParams(1, 2, fgrpFile, 1.0e-8);
  delete fcat3;
  fcat3 = new FragCatalog(fparams);
  ROMol *tmpMol=SmilesToMol("OC(N)CO");
  TEST_ASSERT(tmpMol);
  catGen.addFragsFromMol(*tmpMol, fcat3);
  TEST_ASSERT(fcat3->getNumEntries()==1);
  //std::cout << fcat3->getEntryWithBitId(0)->getDescription() << std::endl;
  TEST_ASSERT(fcat3->getEntryWithBitId(0)->getDescription()=="C<-O>C(<-O>)<-N>");
  BOOST_LOG(rdInfoLog) << "---- Done" << std::endl;

  delete tmpMol;
}

void testIssue294(){
  BOOST_LOG(rdInfoLog) << "---- Test Issue294\n  Watch memory usage." << std::endl;
  std::string rdbase = getenv("RDBASE");
  std::string fname = rdbase + "/Code/GraphMol/FragCatalog/test_data/mols.smi";
  std::string fgrpFile = rdbase + "/Code/GraphMol/FragCatalog/test_data/funcGroups.txt";
  SmilesMolSupplier suppl(fname," ",0,1,false);

  FragCatParams *fparams = new FragCatParams(1, 6, fgrpFile, 1.0e-8);
  FragCatalog fcat(fparams);
  FragCatGenerator catGen;

  std::vector<ROMol *> mols;
  ROMol *m = suppl.next();
  while (m) {
    mols.push_back(m);
    catGen.addFragsFromMol(*m, &fcat);
    try{
      m = suppl.next();
    } catch( FileParseException &) {
      m = NULL;
    }
  }
  int nents = fcat.getNumEntries();
  TEST_ASSERT(nents==21);
  FragFPGenerator fpGen;

  m = mols[0];

  for(unsigned int i=0;i<200;i++){
    for (std::vector<ROMol *>::const_iterator mi = mols.begin();
	 mi != mols.end(); mi++) {
      ExplicitBitVect *fp = fpGen.getFPForMol(*(*mi), fcat);
      delete fp;
    }
  }
  BOOST_LOG(rdInfoLog) << "---- Done" << std::endl;
}

int main() {
  RDLog::InitLogs();
  test1();
  testIssue294();
  return 0;

}

<|endoftext|>


<commit_before>/*=========================================================================

  Program:   ORFEO Toolbox
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) Centre National d'Etudes Spatiales. All rights reserved.
  See OTBCopyright.txt for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

#include "otbMapProjectionWrapper.h"
#include "otbMacro.h"

#include "projection/ossimMapProjection.h"

#include "projection/ossimMapProjectionFactory.h"
#include "projection/ossimMapProjection.h"
#include "base/ossimGpt.h"
#include "base/ossimDpt.h"
#include "projection/ossimProjection.h"
#include "base/ossimEllipsoid.h"
#include "base/ossimEllipsoidFactory.h"
#include "base/ossimString.h"
#include "gdal/ossimOgcWktTranslator.h"

namespace otb
{

MapProjectionWrapper::MapProjectionWrapper():
  m_MapProjection(NULL), m_ProjectionRefWkt(""), reinstanciateProjection(true)
{
}

MapProjectionWrapper::~MapProjectionWrapper()
{
  if (m_MapProjection != NULL)
    {
    delete m_MapProjection;
    }
}

MapProjectionWrapper::InternalMapProjectionPointer MapProjectionWrapper::GetMapProjection()
{
  itkDebugMacro("returning MapProjection address " << this->m_MapProjection);
  if ((reinstanciateProjection) /*|| (m_MapProjection == NULL)*/)
    {
    this->InstanciateProjection();
    }

  return this->m_MapProjection;
}

MapProjectionWrapper::InternalMapProjectionConstPointer MapProjectionWrapper::GetMapProjection() const
{
  itkDebugMacro("returning MapProjection address " << this->m_MapProjection);
  if ((reinstanciateProjection) /*|| (m_MapProjection == NULL)*/)
    {
    itkExceptionMacro(<< "m_MapProjection not up-to-date, call InstanciateProjection() first");
    }

  return this->m_MapProjection;
}

std::string MapProjectionWrapper::GetWkt()
{
  ossimKeywordlist kwl;
  this->GetMapProjection();
  if (m_MapProjection == NULL)
    {
    return "";
    }
  m_MapProjection->saveState(kwl);
  ossimOgcWktTranslator wktTranslator;
  std::string           wkt;
  wkt = wktTranslator.fromOssimKwl(kwl);
  return wkt;
}

void MapProjectionWrapper::SetWkt(std::string projectionRefWkt)
{
  this->m_ProjectionRefWkt = projectionRefWkt;
  reinstanciateProjection = true;
  this->InstanciateProjection();
  this->Modified();
}

bool MapProjectionWrapper::InstanciateProjection()
{
  if ((this->reinstanciateProjection) || (m_MapProjection == NULL))
    {
    ossimKeywordlist      kwl;
    ossimOgcWktTranslator wktTranslator;

    bool projectionInformationAvailable = wktTranslator.toOssimKwl(m_ProjectionRefWkt, kwl);

    if (!projectionInformationAvailable)
      {
      otbMsgDevMacro(<< "WARNING: Impossible to create the projection from string: " << m_ProjectionRefWkt);
      return false;
      }

    //we don't want to have a ossimEquDistCylProjection here:
    //see discussion in May 2009 on ossim list;
    //a better solution might be available...
    std::string projectionString(kwl.find("type"));
    if (projectionString.find("ossimEquDistCylProjection") != string::npos)
      {
      otbMsgDevMacro(<< "WARNING: Not instanciating a ossimEquDistCylProjection: " << projectionString);
      otbMsgDevMacro(<< "Wkt was: " << kwl);
      otbMsgDevMacro(<< "From RefWkt: " << m_ProjectionRefWkt);
      return false;
      }

    m_MapProjection = ossimMapProjectionFactory::instance()->createProjection(kwl);

    this->reinstanciateProjection = false;
    return true;
    }
  return false;
}

void MapProjectionWrapper::InverseTransform(double x, double y, double z,
                                       double& lon, double& lat, double& h)
{
  if (m_MapProjection == NULL)
    {
    otbMsgDevMacro(<< "WARNING: Using identity");
    lon = x;
    lat = y;
    h = z;
    return;
    }

  ossimDpt ossimDPoint(x, y);

  //map projection
  ossimGpt ossimGPoint;
  ossimGPoint = this->GetMapProjection()->inverse(ossimDPoint);
  ossimGPoint.changeDatum(ossimDatumFactory::instance()->wgs84());

  lon = ossimGPoint.lon;
  lat = ossimGPoint.lat;
  h = z;
}

void MapProjectionWrapper::ForwardTransform(double lon, double lat, double h,
                                       double& x, double& y, double& z)
{
  if (m_MapProjection == NULL)
    {
    otbMsgDevMacro(<< "WARNING: Using identity");
    x = lon;
    y = lat;
    z = h;
    return;
    }

  ossimGpt ossimGPoint(lat, lon, h);

  //map projection
  ossimDpt ossimDPoint;
  ossimDPoint = this->GetMapProjection()->forward(ossimGPoint);

  x = ossimDPoint.x;
  y = ossimDPoint.y;
  z = h;
}

void MapProjectionWrapper::PrintMap() const
{
  std::cout << m_MapProjection->print(std::cout);
}
} // namespace otb
<commit_msg>Backed out changeset 32460a398b06<commit_after>/*=========================================================================

  Program:   ORFEO Toolbox
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) Centre National d'Etudes Spatiales. All rights reserved.
  See OTBCopyright.txt for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

#include "otbMapProjectionWrapper.h"
#include "otbMacro.h"

#include "projection/ossimMapProjection.h"

#include "projection/ossimMapProjectionFactory.h"
#include "projection/ossimMapProjection.h"
#include "base/ossimGpt.h"
#include "base/ossimDpt.h"
#include "projection/ossimProjection.h"
#include "base/ossimEllipsoid.h"
#include "base/ossimEllipsoidFactory.h"
#include "base/ossimString.h"
#include "gdal/ossimOgcWktTranslator.h"

namespace otb
{

MapProjectionWrapper::MapProjectionWrapper():
  m_MapProjection(NULL), m_ProjectionRefWkt(""), reinstanciateProjection(true)
{
}

MapProjectionWrapper::~MapProjectionWrapper()
{
  if (m_MapProjection != NULL)
    {
    delete m_MapProjection;
    }
}

MapProjectionWrapper::InternalMapProjectionPointer MapProjectionWrapper::GetMapProjection()
{
  itkDebugMacro("returning MapProjection address " << this->m_MapProjection);
  if ((reinstanciateProjection) || (m_MapProjection == NULL))
    {
    this->InstanciateProjection();
    }

  return this->m_MapProjection;
}

MapProjectionWrapper::InternalMapProjectionConstPointer MapProjectionWrapper::GetMapProjection() const
{
  itkDebugMacro("returning MapProjection address " << this->m_MapProjection);
  if ((reinstanciateProjection) || (m_MapProjection == NULL))
    {
    itkExceptionMacro(<< "m_MapProjection not up-to-date, call InstanciateProjection() first");
    }

  return this->m_MapProjection;
}

std::string MapProjectionWrapper::GetWkt()
{
  ossimKeywordlist kwl;
  this->GetMapProjection();
  if (m_MapProjection == NULL)
    {
    return "";
    }
  m_MapProjection->saveState(kwl);
  ossimOgcWktTranslator wktTranslator;
  std::string           wkt;
  wkt = wktTranslator.fromOssimKwl(kwl);
  return wkt;
}

void MapProjectionWrapper::SetWkt(std::string projectionRefWkt)
{
  this->m_ProjectionRefWkt = projectionRefWkt;
  reinstanciateProjection = true;
  this->InstanciateProjection();
  this->Modified();
}

bool MapProjectionWrapper::InstanciateProjection()
{
  if ((this->reinstanciateProjection) || (m_MapProjection == NULL))
    {
    ossimKeywordlist      kwl;
    ossimOgcWktTranslator wktTranslator;

    bool projectionInformationAvailable = wktTranslator.toOssimKwl(m_ProjectionRefWkt, kwl);

    if (!projectionInformationAvailable)
      {
      otbMsgDevMacro(<< "WARNING: Impossible to create the projection from string: " << m_ProjectionRefWkt);
      return false;
      }

    //we don't want to have a ossimEquDistCylProjection here:
    //see discussion in May 2009 on ossim list;
    //a better solution might be available...
    std::string projectionString(kwl.find("type"));
    if (projectionString.find("ossimEquDistCylProjection") != string::npos)
      {
      otbMsgDevMacro(<< "WARNING: Not instanciating a ossimEquDistCylProjection: " << projectionString);
      otbMsgDevMacro(<< "Wkt was: " << kwl);
      otbMsgDevMacro(<< "From RefWkt: " << m_ProjectionRefWkt);
      return false;
      }

    m_MapProjection = ossimMapProjectionFactory::instance()->createProjection(kwl);

    this->reinstanciateProjection = false;
    return true;
    }
  return false;
}

void MapProjectionWrapper::InverseTransform(double x, double y, double z,
                                       double& lon, double& lat, double& h)
{
  if (m_MapProjection == NULL)
    {
    otbMsgDevMacro(<< "WARNING: Using identity");
    lon = x;
    lat = y;
    h = z;
    return;
    }

  ossimDpt ossimDPoint(x, y);

  //map projection
  ossimGpt ossimGPoint;
  ossimGPoint = this->GetMapProjection()->inverse(ossimDPoint);
  ossimGPoint.changeDatum(ossimDatumFactory::instance()->wgs84());

  lon = ossimGPoint.lon;
  lat = ossimGPoint.lat;
  h = z;
}

void MapProjectionWrapper::ForwardTransform(double lon, double lat, double h,
                                       double& x, double& y, double& z)
{
  if (m_MapProjection == NULL)
    {
    otbMsgDevMacro(<< "WARNING: Using identity");
    x = lon;
    y = lat;
    z = h;
    return;
    }

  ossimGpt ossimGPoint(lat, lon, h);

  //map projection
  ossimDpt ossimDPoint;
  ossimDPoint = this->GetMapProjection()->forward(ossimGPoint);

  x = ossimDPoint.x;
  y = ossimDPoint.y;
  z = h;
}

void MapProjectionWrapper::PrintMap() const
{
  std::cout << m_MapProjection->print(std::cout);
}
} // namespace otb
<|endoftext|>


<commit_before>//------------------------------------------------------------------------------------------------------------
//* Copyright  2010-2013 Immersive and Creative Technologies Lab, Cyprus University of Technology           *
//* Link: http://ict.cut.ac.cy                                                                               *
//* Software developer(s): Kyriakos Herakleous                                                               *
//* Researcher(s): Kyriakos Herakleous, Charalambos Poullis                                                  *
//*                                                                                *
//* This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License.*
//* Link: http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en_US                                        *
//------------------------------------------------------------------------------------------------------------

#include "stdafx.h"
#include "GrayCodes.h"

GrayCodes::GrayCodes(int projW, int projH)
{
	for (int i=0; i<GRAY_MAX_NUM; i++)
	{
		grayCodes[i]=NULL;

	}

	height=projH;
	width=projW;

	imgsLoaded=false;

	calNumOfImgs();

	currentImgNum=0;

}

GrayCodes::~GrayCodes()
{
	if(imgsLoaded)
		unload();
}

int GrayCodes::getNumOfColBits()
{
	return numOfColImgs;
}

int GrayCodes::getNumOfRowBits()
{
	return numOfRowImgs;
}

void GrayCodes::calNumOfImgs()
{
	numOfColImgs = (int)ceil(log(double (width))/log(2.0));
	numOfRowImgs = (int)ceil(log(double (height))/log(2.0));

	numOfImgs= 2 + 2*numOfColImgs + 2*numOfRowImgs;
}

void GrayCodes::unload()
{

	for(int i=0; i < numOfImgs;i++ )
	{
		if(grayCodes[i])
		{
			cvReleaseImage(&grayCodes[i]);
			grayCodes[i]=NULL;
		}
	}
	imgsLoaded=false;
}

IplImage* GrayCodes::getImg(int num)
{
	if(num<numOfImgs)
	{
		currentImgNum = num;
		return grayCodes[num];
	}
	else
		return NULL;
}

IplImage* GrayCodes::getNextImg()
{

	if(currentImgNum<numOfImgs)
	{
		currentImgNum++;
		return grayCodes[currentImgNum-1];
	}
	else
		return NULL;
}

int GrayCodes::getNumOfImgs()
{
	return numOfImgs;
}

void GrayCodes::allocMemForImgs()
{

	for(int i=0; i<numOfImgs; i++)
	{
		grayCodes[i]=cvCreateImage(cvSize(width,height),IPL_DEPTH_8U,1);
	}
	imgsLoaded=true;
}

void GrayCodes::generateGrays()
{
	if(!imgsLoaded)
	{
		allocMemForImgs();
	}

	//generate all white and all black images
	for (int j=0; j<width; j++)
	{
		for (int i=0;i<height;i++)
		{
			CvScalar pixel_color;
			pixel_color.val[0] = 255;
			cvSet2D(grayCodes[0], i, j, pixel_color);

			pixel_color.val[0] = 0;
			cvSet2D(grayCodes[1], i, j, pixel_color);
		}
	}

	int flag=0;

	for (int j=0; j<width; j++)
	{
		int rem=0, num=j, prevRem=j%2;

		for (int k=0; k<numOfColImgs; k++)
		{

			num=num/2;
			rem=num%2;

			if ((rem==0 && prevRem==1) || (rem==1 && prevRem==0))
			{
				flag=1;
			}
			else
			{
				flag= 0;
			}

			for (int i=0;i<height;i++)
			{
				CvScalar pixel_color;
				pixel_color.val[0] = float(flag*255);
				cvSet2D(grayCodes[2*numOfColImgs-2*k], i, j, pixel_color);

				if(pixel_color.val[0]>0)
					pixel_color.val[0]=0;
				else
					pixel_color.val[0]=255;

				cvSet2D(grayCodes[2*numOfColImgs-2*k+1], i, j, pixel_color);
			}

			prevRem=rem;
		}

	}

	for (int i=0;i<height;i++)
	{
		int rem=0, num=i, prevRem=i%2;

		for (int k=0; k<numOfRowImgs; k++)
		{

			num=num/2;
			rem=num%2;

			if ((rem==0 && prevRem==1) || (rem==1 && prevRem==0))
			{
				flag=1;
			}
			else
			{
				flag= 0;
			}

			for (int j=0; j<width; j++)
			{
				CvScalar pixel_color;
				pixel_color.val[0] = float(flag*255);
				cvSet2D(grayCodes[2*numOfRowImgs-2*k+2*numOfColImgs], i, j, pixel_color);

				if(pixel_color.val[0]>0)
					pixel_color.val[0]=0;
				else
					pixel_color.val[0]=255;

				cvSet2D(grayCodes[2*numOfRowImgs-2*k+2*numOfColImgs+1], i, j, pixel_color);
			}

			prevRem=rem;
		}

	}
}

void GrayCodes::save()
{
	for(int i = 0; i < numOfImgs; i++)
	{
		std::stringstream path;

		if(i+1<10)
			path<<"0";

		path<< i+1 <<".png";

		cvSaveImage(path.str().c_str(),grayCodes[i]);
	}
}

//convert a gray code sequence to a decimal number
int GrayCodes::grayToDec(cv::vector<bool> gray)
{
	int dec=0;
	bool tmp = gray[0];

	if(tmp)
		dec+=(int) pow((float)2,int (gray.size() -1));

	for(int i=1; i< gray.size(); i++)
	{
		tmp=Utilities::XOR(tmp,gray[i]);

		if(tmp)
			dec+= (int) pow((float)2,int (gray.size()-i-1) );
	}
	return dec;
}

<commit_msg>Create GrayCodes.cpp<commit_after>//------------------------------------------------------------------------------------------------------------
//* Copyright © 2010-2015 Immersive and Creative Technologies Lab, Cyprus University of Technology           *
//* Link: http://www.theICTlab.org                                                                           *
//* Software developer(s): Kyriakos Herakleous                                                               *
//* Researcher(s): Kyriakos Herakleous, Charalambos Poullis                                                  *
//*                                                                                *
//* License: Check the file License.md                                                                       *
//------------------------------------------------------------------------------------------------------------

#include "stdafx.h"
#include "GrayCodes.h"

GrayCodes::GrayCodes(int projW, int projH)
{
	for (int i=0; i<GRAY_MAX_NUM; i++)
	{
		grayCodes[i]=NULL;

	}

	height=projH;
	width=projW;

	imgsLoaded=false;

	calNumOfImgs();

	currentImgNum=0;

}

GrayCodes::~GrayCodes()
{
	if(imgsLoaded)
		unload();
}

int GrayCodes::getNumOfColBits()
{
	return numOfColImgs;
}

int GrayCodes::getNumOfRowBits()
{
	return numOfRowImgs;
}

void GrayCodes::calNumOfImgs()
{
	numOfColImgs = (int)ceil(log(double (width))/log(2.0));
	numOfRowImgs = (int)ceil(log(double (height))/log(2.0));

	numOfImgs= 2 + 2*numOfColImgs + 2*numOfRowImgs;
}

void GrayCodes::unload()
{

	for(int i=0; i < numOfImgs;i++ )
	{
		if(grayCodes[i])
		{
			cvReleaseImage(&grayCodes[i]);
			grayCodes[i]=NULL;
		}
	}
	imgsLoaded=false;
}

IplImage* GrayCodes::getImg(int num)
{
	if(num<numOfImgs)
	{
		currentImgNum = num;
		return grayCodes[num];
	}
	else
		return NULL;
}

IplImage* GrayCodes::getNextImg()
{

	if(currentImgNum<numOfImgs)
	{
		currentImgNum++;
		return grayCodes[currentImgNum-1];
	}
	else
		return NULL;
}

int GrayCodes::getNumOfImgs()
{
	return numOfImgs;
}

void GrayCodes::allocMemForImgs()
{

	for(int i=0; i<numOfImgs; i++)
	{
		grayCodes[i]=cvCreateImage(cvSize(width,height),IPL_DEPTH_8U,1);
	}
	imgsLoaded=true;
}

void GrayCodes::generateGrays()
{
	if(!imgsLoaded)
	{
		allocMemForImgs();
	}

	//generate all white and all black images
	for (int j=0; j<width; j++)
	{
		for (int i=0;i<height;i++)
		{
			CvScalar pixel_color;
			pixel_color.val[0] = 255;
			cvSet2D(grayCodes[0], i, j, pixel_color);

			pixel_color.val[0] = 0;
			cvSet2D(grayCodes[1], i, j, pixel_color);
		}
	}

	int flag=0;

	for (int j=0; j<width; j++)
	{
		int rem=0, num=j, prevRem=j%2;

		for (int k=0; k<numOfColImgs; k++)
		{

			num=num/2;
			rem=num%2;

			if ((rem==0 && prevRem==1) || (rem==1 && prevRem==0))
			{
				flag=1;
			}
			else
			{
				flag= 0;
			}

			for (int i=0;i<height;i++)
			{
				CvScalar pixel_color;
				pixel_color.val[0] = float(flag*255);
				cvSet2D(grayCodes[2*numOfColImgs-2*k], i, j, pixel_color);

				if(pixel_color.val[0]>0)
					pixel_color.val[0]=0;
				else
					pixel_color.val[0]=255;

				cvSet2D(grayCodes[2*numOfColImgs-2*k+1], i, j, pixel_color);
			}

			prevRem=rem;
		}

	}

	for (int i=0;i<height;i++)
	{
		int rem=0, num=i, prevRem=i%2;

		for (int k=0; k<numOfRowImgs; k++)
		{

			num=num/2;
			rem=num%2;

			if ((rem==0 && prevRem==1) || (rem==1 && prevRem==0))
			{
				flag=1;
			}
			else
			{
				flag= 0;
			}

			for (int j=0; j<width; j++)
			{
				CvScalar pixel_color;
				pixel_color.val[0] = float(flag*255);
				cvSet2D(grayCodes[2*numOfRowImgs-2*k+2*numOfColImgs], i, j, pixel_color);

				if(pixel_color.val[0]>0)
					pixel_color.val[0]=0;
				else
					pixel_color.val[0]=255;

				cvSet2D(grayCodes[2*numOfRowImgs-2*k+2*numOfColImgs+1], i, j, pixel_color);
			}

			prevRem=rem;
		}

	}
}

void GrayCodes::save()
{
	for(int i = 0; i < numOfImgs; i++)
	{
		std::stringstream path;

		if(i+1<10)
			path<<"0";

		path<< i+1 <<".png";

		cvSaveImage(path.str().c_str(),grayCodes[i]);
	}
}

//convert a gray code sequence to a decimal number
int GrayCodes::grayToDec(cv::vector<bool> gray)
{
	int dec=0;
	bool tmp = gray[0];

	if(tmp)
		dec+=(int) pow((float)2,int (gray.size() -1));

	for(int i=1; i< gray.size(); i++)
	{
		tmp=Utilities::XOR(tmp,gray[i]);

		if(tmp)
			dec+= (int) pow((float)2,int (gray.size()-i-1) );
	}
	return dec;
}

<|endoftext|>


<commit_before>/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * Modified by Cloudius Systems.
 * Copyright 2015 Cloudius Systems.
 */

#pragma once

#include "gms/i_endpoint_state_change_subscriber.hh"
#include "core/distributed.hh"
#include "message/messaging_service.hh"
#include "utils/UUID.hh"
#include "streaming/stream_session_state.hh"
#include "streaming/connection_handler.hh"
#include "streaming/stream_transfer_task.hh"
#include "streaming/stream_receive_task.hh"
#include "streaming/stream_request.hh"
#include "streaming/messages/incoming_file_message.hh"
#include "streaming/stream_detail.hh"
#include "sstables/sstables.hh"
#include "query-request.hh"
#include "dht/i_partitioner.hh"
#include <map>
#include <vector>

namespace streaming {

class stream_result_future;

/**
 * Handles the streaming a one or more section of one of more sstables to and from a specific
 * remote node.
 *
 * Both this node and the remote one will create a similar symmetrical StreamSession. A streaming
 * session has the following life-cycle:
 *
 * 1. Connections Initialization
 *
 *   (a) A node (the initiator in the following) create a new StreamSession, initialize it (init())
 *       and then start it (start()). Start will create a {@link ConnectionHandler} that will create
 *       two connections to the remote node (the follower in the following) with whom to stream and send
 *       a StreamInit message. The first connection will be the incoming connection for the
 *       initiator, and the second connection will be the outgoing.
 *   (b) Upon reception of that StreamInit message, the follower creates its own StreamSession,
 *       initialize it if it still does not exist, and attach connecting socket to its ConnectionHandler
 *       according to StreamInit message's isForOutgoing flag.
 *   (d) When the both incoming and outgoing connections are established, StreamSession calls
 *       StreamSession#onInitializationComplete method to start the streaming prepare phase
 *       (StreamResultFuture.startStreaming()).
 *
 * 2. Streaming preparation phase
 *
 *   (a) This phase is started when the initiator onInitializationComplete() method is called. This method sends a
 *       PrepareMessage that includes what files/sections this node will stream to the follower
 *       (stored in a StreamTransferTask, each column family has it's own transfer task) and what
 *       the follower needs to stream back (StreamReceiveTask, same as above). If the initiator has
 *       nothing to receive from the follower, it goes directly to its Streaming phase. Otherwise,
 *       it waits for the follower PrepareMessage.
 *   (b) Upon reception of the PrepareMessage, the follower records which files/sections it will receive
 *       and send back its own PrepareMessage with a summary of the files/sections that will be sent to
 *       the initiator (prepare()). After having sent that message, the follower goes to its Streamning
 *       phase.
 *   (c) When the initiator receives the follower PrepareMessage, it records which files/sections it will
 *       receive and then goes to his own Streaming phase.
 *
 * 3. Streaming phase
 *
 *   (a) The streaming phase is started by each node (the sender in the follower, but note that each side
 *       of the StreamSession may be sender for some of the files) involved by calling startStreamingFiles().
 *       This will sequentially send a FileMessage for each file of each SteamTransferTask. Each FileMessage
 *       consists of a FileMessageHeader that indicates which file is coming and then start streaming the
 *       content for that file (StreamWriter in FileMessage.serialize()). When a file is fully sent, the
 *       fileSent() method is called for that file. If all the files for a StreamTransferTask are sent
 *       (StreamTransferTask.complete()), the task is marked complete (taskCompleted()).
 *   (b) On the receiving side, a SSTable will be written for the incoming file (StreamReader in
 *       FileMessage.deserialize()) and once the FileMessage is fully received, the file will be marked as
 *       complete (received()). When all files for the StreamReceiveTask have been received, the sstables
 *       are added to the CFS (and 2ndary index are built, StreamReceiveTask.complete()) and the task
 *       is marked complete (taskCompleted())
 *   (b) If during the streaming of a particular file an I/O error occurs on the receiving end of a stream
 *       (FileMessage.deserialize), the node will retry the file (up to DatabaseDescriptor.getMaxStreamingRetries())
 *       by sending a RetryMessage to the sender. On receiving a RetryMessage, the sender simply issue a new
 *       FileMessage for that file.
 *   (c) When all transfer and receive tasks for a session are complete, the move to the Completion phase
 *       (maybeCompleted()).
 *
 * 4. Completion phase
 *
 *   (a) When a node has finished all transfer and receive task, it enter the completion phase (maybeCompleted()).
 *       If it had already received a CompleteMessage from the other side (it is in the WAIT_COMPLETE state), that
 *       session is done is is closed (closeSession()). Otherwise, the node switch to the WAIT_COMPLETE state and
 *       send a CompleteMessage to the other side.
 */
class stream_session : public gms::i_endpoint_state_change_subscriber {
private:
    using messaging_verb = net::messaging_verb;
    using messaging_service = net::messaging_service;
    using shard_id = net::messaging_service::shard_id;
    using inet_address = gms::inet_address;
    using endpoint_state = gms::endpoint_state;
    using application_state = gms::application_state;
    using versioned_value = gms::versioned_value;
    using UUID = utils::UUID;
    using token = dht::token;
    using ring_position = dht::ring_position;
    class handler {
    public:
        future<> stop() {
            return make_ready_future<>();
        }
    };
    static net::messaging_service& ms() {
        return net::get_local_messaging_service();
    }
    static distributed<handler> _handlers;
    static void init_messaging_service_handler();
    static distributed<database>* _db;
    static database& get_local_db() { return _db->local(); }
public:
    static future<> init_streaming_service(distributed<database>& db);
public:
    /**
     * Streaming endpoint.
     *
     * Each {@code StreamSession} is identified by this InetAddress which is broadcast address of the node streaming.
     */
    inet_address peer;
    /** Actual connecting address. Can be the same as {@linkplain #peer}. */
    inet_address connecting;
    connection_handler conn_handler;
private:
    int _index;
    // should not be null when session is started
    shared_ptr<stream_result_future> _stream_result;

    // stream requests to send to the peer
    std::vector<stream_request> _requests;
    // streaming tasks are created and managed per ColumnFamily ID
    std::map<UUID, stream_transfer_task> _transfers;
    // data receivers, filled after receiving prepare message
    std::map<UUID, stream_receive_task> _receivers;
    //private final StreamingMetrics metrics;
    /* can be null when session is created in remote */
    //private final StreamConnectionFactory factory;

    int _retries;
    bool _is_aborted =  false;
    bool _keep_ss_table_level;

    stream_session_state _state = stream_session_state::INITIALIZED;
    bool _complete_sent = false;
public:
    stream_session() : conn_handler(*this) { }
    /**
     * Create new streaming session with the peer.
     *
     * @param peer Address of streaming peer
     * @param connecting Actual connecting address
     * @param factory is used for establishing connection
     */
    stream_session(inet_address peer_, inet_address connecting_, int index_, bool keep_ss_table_level_)
        : peer(peer_)
        , connecting(connecting_)
        , conn_handler(*this)
        , _index(index_)
        , _keep_ss_table_level(keep_ss_table_level_) {
        //this.metrics = StreamingMetrics.get(connecting);
    }

    UUID plan_id();

    int session_index() {
        return _index;
    }

    sstring description();

public:
    bool keep_ss_table_level() {
        return _keep_ss_table_level;
    }
    /**
     * Bind this session to report to specific {@link StreamResultFuture} and
     * perform pre-streaming initialization.
     *
     * @param streamResult result to report to
     */
    void init(shared_ptr<stream_result_future> stream_result_);

    void start();
#if 0
    public Socket createConnection() throws IOException
    {
        assert factory != null;
        return factory.createConnection(connecting);
    }
#endif

    /**
     * Request data fetch task to this session.
     *
     * @param keyspace Requesting keyspace
     * @param ranges Ranges to retrieve data
     * @param columnFamilies ColumnFamily names. Can be empty if requesting all CF under the keyspace.
     */
    void add_stream_request(sstring keyspace, std::vector<query::range<token>> ranges, std::vector<sstring> column_families, long repaired_at) {
        _requests.emplace_back(std::move(keyspace), std::move(ranges), std::move(column_families), repaired_at);
    }

    /**
     * Set up transfer for specific keyspace/ranges/CFs
     *
     * Used in repair - a streamed sstable in repair will be marked with the given repairedAt time
     *
     * @param keyspace Transfer keyspace
     * @param ranges Transfer ranges
     * @param columnFamilies Transfer ColumnFamilies
     * @param flushTables flush tables?
     * @param repairedAt the time the repair started.
     */
    void add_transfer_ranges(sstring keyspace, std::vector<query::range<token>> ranges, std::vector<sstring> column_families, bool flush_tables, long repaired_at);

    std::vector<column_family*> get_column_family_stores(const sstring& keyspace, const std::vector<sstring>& column_families);

    void add_transfer_files(std::vector<stream_detail> sstable_details);

private:
    void close_session(stream_session_state final_state);

public:
    /**
     * Set current state to {@code newState}.
     *
     * @param newState new state to set
     */
    void set_state(stream_session_state new_state) {
        _state = new_state;
    }

    /**
     * @return current state
     */
    stream_session_state get_state() {
        return _state;
    }

    /**
     * Return if this session completed successfully.
     *
     * @return true if session completed successfully.
     */
    bool is_success() {
        return _state == stream_session_state::COMPLETE;
    }

#if 0
    public void messageReceived(StreamMessage message)
    {
        switch (message.type)
        {
            case PREPARE:
                PrepareMessage msg = (PrepareMessage) message;
                prepare(msg.requests, msg.summaries);
                break;

            case FILE:
                receive((IncomingFileMessage) message);
                break;

            case RECEIVED:
                ReceivedMessage received = (ReceivedMessage) message;
                received(received.cfId, received.sequenceNumber);
                break;

            case RETRY:
                RetryMessage retry = (RetryMessage) message;
                retry(retry.cfId, retry.sequenceNumber);
                break;

            case COMPLETE:
                complete();
                break;

            case SESSION_FAILED:
                sessionFailed();
                break;
        }
    }
#endif
    /**
     * Call back when connection initialization is complete to start the prepare phase.
     */
    void on_initialization_complete();

    /**l
     * Call back for handling exception during streaming.
     *
     * @param e thrown exception
     */
    void on_error();

    /**
     * Prepare this session for sending/receiving files.
     */
    void prepare(std::vector<stream_request> requests, std::vector<stream_summary> summaries);

    /**
     * Call back after sending FileMessageHeader.
     *
     * @param header sent header
     */
    void file_sent(const messages::file_message_header& header);

    /**
     * Call back after receiving FileMessageHeader.
     *
     * @param message received file
     */
    void receive(messages::incoming_file_message message);

    void progress(/* Descriptor desc */ progress_info::direction dir, long bytes, long total);

    void received(UUID cf_id, int sequence_number);

    /**
     * Call back on receiving {@code StreamMessage.Type.RETRY} message.
     *
     * @param cfId ColumnFamily ID
     * @param sequenceNumber Sequence number to indicate which file to stream again
     */
    void retry(UUID cf_id, int sequence_number);

    /**
     * Check if session is completed on receiving {@code StreamMessage.Type.COMPLETE} message.
     */
    void complete();

    /**
     * Call back on receiving {@code StreamMessage.Type.SESSION_FAILED} message.
     */
    void session_failed();

#if 0
    public void doRetry(FileMessageHeader header, Throwable e)
    {
        logger.warn("[Stream #{}] Retrying for following error", planId(), e);
        // retry
        retries++;
        if (retries > DatabaseDescriptor.getMaxStreamingRetries())
            onError(new IOException("Too many retries for " + header, e));
        else
            handler.sendMessage(new RetryMessage(header.cfId, header.sequenceNumber));
    }
#endif

    /**
     * @return Current snapshot of this session info.
     */
    session_info get_session_info();

    void task_completed(stream_receive_task& completed_task);

    void task_completed(stream_transfer_task& completed_task);

public:
    virtual void on_join(inet_address endpoint, endpoint_state ep_state) override {}
    virtual void before_change(inet_address endpoint, endpoint_state current_state, application_state new_state_key, versioned_value new_value) override {}
    virtual void on_change(inet_address endpoint, application_state state, versioned_value value) override {}
    virtual void on_alive(inet_address endpoint, endpoint_state state) override {}
    virtual void on_dead(inet_address endpoint, endpoint_state state) override {}
    virtual void on_remove(inet_address endpoint) override { close_session(stream_session_state::FAILED); }
    virtual void on_restart(inet_address endpoint, endpoint_state ep_state) override { close_session(stream_session_state::FAILED); }

private:
    bool maybe_completed();
#if 0

    /**
     * Flushes matching column families from the given keyspace, or all columnFamilies
     * if the cf list is empty.
     */
    private void flushSSTables(Iterable<ColumnFamilyStore> stores)
    {
        List<Future<?>> flushes = new ArrayList<>();
        for (ColumnFamilyStore cfs : stores)
            flushes.add(cfs.forceFlush());
        FBUtilities.waitOnFutures(flushes);
    }
#endif
    void prepare_receiving(stream_summary& summary);
    void start_streaming_files();
};

} // namespace streaming
<commit_msg>streaming: Make get_local_db() and ms() public<commit_after>/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * Modified by Cloudius Systems.
 * Copyright 2015 Cloudius Systems.
 */

#pragma once

#include "gms/i_endpoint_state_change_subscriber.hh"
#include "core/distributed.hh"
#include "message/messaging_service.hh"
#include "utils/UUID.hh"
#include "streaming/stream_session_state.hh"
#include "streaming/connection_handler.hh"
#include "streaming/stream_transfer_task.hh"
#include "streaming/stream_receive_task.hh"
#include "streaming/stream_request.hh"
#include "streaming/messages/incoming_file_message.hh"
#include "streaming/stream_detail.hh"
#include "sstables/sstables.hh"
#include "query-request.hh"
#include "dht/i_partitioner.hh"
#include <map>
#include <vector>

namespace streaming {

class stream_result_future;

/**
 * Handles the streaming a one or more section of one of more sstables to and from a specific
 * remote node.
 *
 * Both this node and the remote one will create a similar symmetrical StreamSession. A streaming
 * session has the following life-cycle:
 *
 * 1. Connections Initialization
 *
 *   (a) A node (the initiator in the following) create a new StreamSession, initialize it (init())
 *       and then start it (start()). Start will create a {@link ConnectionHandler} that will create
 *       two connections to the remote node (the follower in the following) with whom to stream and send
 *       a StreamInit message. The first connection will be the incoming connection for the
 *       initiator, and the second connection will be the outgoing.
 *   (b) Upon reception of that StreamInit message, the follower creates its own StreamSession,
 *       initialize it if it still does not exist, and attach connecting socket to its ConnectionHandler
 *       according to StreamInit message's isForOutgoing flag.
 *   (d) When the both incoming and outgoing connections are established, StreamSession calls
 *       StreamSession#onInitializationComplete method to start the streaming prepare phase
 *       (StreamResultFuture.startStreaming()).
 *
 * 2. Streaming preparation phase
 *
 *   (a) This phase is started when the initiator onInitializationComplete() method is called. This method sends a
 *       PrepareMessage that includes what files/sections this node will stream to the follower
 *       (stored in a StreamTransferTask, each column family has it's own transfer task) and what
 *       the follower needs to stream back (StreamReceiveTask, same as above). If the initiator has
 *       nothing to receive from the follower, it goes directly to its Streaming phase. Otherwise,
 *       it waits for the follower PrepareMessage.
 *   (b) Upon reception of the PrepareMessage, the follower records which files/sections it will receive
 *       and send back its own PrepareMessage with a summary of the files/sections that will be sent to
 *       the initiator (prepare()). After having sent that message, the follower goes to its Streamning
 *       phase.
 *   (c) When the initiator receives the follower PrepareMessage, it records which files/sections it will
 *       receive and then goes to his own Streaming phase.
 *
 * 3. Streaming phase
 *
 *   (a) The streaming phase is started by each node (the sender in the follower, but note that each side
 *       of the StreamSession may be sender for some of the files) involved by calling startStreamingFiles().
 *       This will sequentially send a FileMessage for each file of each SteamTransferTask. Each FileMessage
 *       consists of a FileMessageHeader that indicates which file is coming and then start streaming the
 *       content for that file (StreamWriter in FileMessage.serialize()). When a file is fully sent, the
 *       fileSent() method is called for that file. If all the files for a StreamTransferTask are sent
 *       (StreamTransferTask.complete()), the task is marked complete (taskCompleted()).
 *   (b) On the receiving side, a SSTable will be written for the incoming file (StreamReader in
 *       FileMessage.deserialize()) and once the FileMessage is fully received, the file will be marked as
 *       complete (received()). When all files for the StreamReceiveTask have been received, the sstables
 *       are added to the CFS (and 2ndary index are built, StreamReceiveTask.complete()) and the task
 *       is marked complete (taskCompleted())
 *   (b) If during the streaming of a particular file an I/O error occurs on the receiving end of a stream
 *       (FileMessage.deserialize), the node will retry the file (up to DatabaseDescriptor.getMaxStreamingRetries())
 *       by sending a RetryMessage to the sender. On receiving a RetryMessage, the sender simply issue a new
 *       FileMessage for that file.
 *   (c) When all transfer and receive tasks for a session are complete, the move to the Completion phase
 *       (maybeCompleted()).
 *
 * 4. Completion phase
 *
 *   (a) When a node has finished all transfer and receive task, it enter the completion phase (maybeCompleted()).
 *       If it had already received a CompleteMessage from the other side (it is in the WAIT_COMPLETE state), that
 *       session is done is is closed (closeSession()). Otherwise, the node switch to the WAIT_COMPLETE state and
 *       send a CompleteMessage to the other side.
 */
class stream_session : public gms::i_endpoint_state_change_subscriber {
private:
    using messaging_verb = net::messaging_verb;
    using messaging_service = net::messaging_service;
    using shard_id = net::messaging_service::shard_id;
    using inet_address = gms::inet_address;
    using endpoint_state = gms::endpoint_state;
    using application_state = gms::application_state;
    using versioned_value = gms::versioned_value;
    using UUID = utils::UUID;
    using token = dht::token;
    using ring_position = dht::ring_position;
    class handler {
    public:
        future<> stop() {
            return make_ready_future<>();
        }
    };
    static distributed<handler> _handlers;
    static void init_messaging_service_handler();
    static distributed<database>* _db;
public:
    static net::messaging_service& ms() {
        return net::get_local_messaging_service();
    }
    static database& get_local_db() { return _db->local(); }
    static future<> init_streaming_service(distributed<database>& db);
public:
    /**
     * Streaming endpoint.
     *
     * Each {@code StreamSession} is identified by this InetAddress which is broadcast address of the node streaming.
     */
    inet_address peer;
    /** Actual connecting address. Can be the same as {@linkplain #peer}. */
    inet_address connecting;
    connection_handler conn_handler;
private:
    int _index;
    // should not be null when session is started
    shared_ptr<stream_result_future> _stream_result;

    // stream requests to send to the peer
    std::vector<stream_request> _requests;
    // streaming tasks are created and managed per ColumnFamily ID
    std::map<UUID, stream_transfer_task> _transfers;
    // data receivers, filled after receiving prepare message
    std::map<UUID, stream_receive_task> _receivers;
    //private final StreamingMetrics metrics;
    /* can be null when session is created in remote */
    //private final StreamConnectionFactory factory;

    int _retries;
    bool _is_aborted =  false;
    bool _keep_ss_table_level;

    stream_session_state _state = stream_session_state::INITIALIZED;
    bool _complete_sent = false;
public:
    stream_session() : conn_handler(*this) { }
    /**
     * Create new streaming session with the peer.
     *
     * @param peer Address of streaming peer
     * @param connecting Actual connecting address
     * @param factory is used for establishing connection
     */
    stream_session(inet_address peer_, inet_address connecting_, int index_, bool keep_ss_table_level_)
        : peer(peer_)
        , connecting(connecting_)
        , conn_handler(*this)
        , _index(index_)
        , _keep_ss_table_level(keep_ss_table_level_) {
        //this.metrics = StreamingMetrics.get(connecting);
    }

    UUID plan_id();

    int session_index() {
        return _index;
    }

    sstring description();

public:
    bool keep_ss_table_level() {
        return _keep_ss_table_level;
    }
    /**
     * Bind this session to report to specific {@link StreamResultFuture} and
     * perform pre-streaming initialization.
     *
     * @param streamResult result to report to
     */
    void init(shared_ptr<stream_result_future> stream_result_);

    void start();
#if 0
    public Socket createConnection() throws IOException
    {
        assert factory != null;
        return factory.createConnection(connecting);
    }
#endif

    /**
     * Request data fetch task to this session.
     *
     * @param keyspace Requesting keyspace
     * @param ranges Ranges to retrieve data
     * @param columnFamilies ColumnFamily names. Can be empty if requesting all CF under the keyspace.
     */
    void add_stream_request(sstring keyspace, std::vector<query::range<token>> ranges, std::vector<sstring> column_families, long repaired_at) {
        _requests.emplace_back(std::move(keyspace), std::move(ranges), std::move(column_families), repaired_at);
    }

    /**
     * Set up transfer for specific keyspace/ranges/CFs
     *
     * Used in repair - a streamed sstable in repair will be marked with the given repairedAt time
     *
     * @param keyspace Transfer keyspace
     * @param ranges Transfer ranges
     * @param columnFamilies Transfer ColumnFamilies
     * @param flushTables flush tables?
     * @param repairedAt the time the repair started.
     */
    void add_transfer_ranges(sstring keyspace, std::vector<query::range<token>> ranges, std::vector<sstring> column_families, bool flush_tables, long repaired_at);

    std::vector<column_family*> get_column_family_stores(const sstring& keyspace, const std::vector<sstring>& column_families);

    void add_transfer_files(std::vector<stream_detail> sstable_details);

private:
    void close_session(stream_session_state final_state);

public:
    /**
     * Set current state to {@code newState}.
     *
     * @param newState new state to set
     */
    void set_state(stream_session_state new_state) {
        _state = new_state;
    }

    /**
     * @return current state
     */
    stream_session_state get_state() {
        return _state;
    }

    /**
     * Return if this session completed successfully.
     *
     * @return true if session completed successfully.
     */
    bool is_success() {
        return _state == stream_session_state::COMPLETE;
    }

#if 0
    public void messageReceived(StreamMessage message)
    {
        switch (message.type)
        {
            case PREPARE:
                PrepareMessage msg = (PrepareMessage) message;
                prepare(msg.requests, msg.summaries);
                break;

            case FILE:
                receive((IncomingFileMessage) message);
                break;

            case RECEIVED:
                ReceivedMessage received = (ReceivedMessage) message;
                received(received.cfId, received.sequenceNumber);
                break;

            case RETRY:
                RetryMessage retry = (RetryMessage) message;
                retry(retry.cfId, retry.sequenceNumber);
                break;

            case COMPLETE:
                complete();
                break;

            case SESSION_FAILED:
                sessionFailed();
                break;
        }
    }
#endif
    /**
     * Call back when connection initialization is complete to start the prepare phase.
     */
    void on_initialization_complete();

    /**l
     * Call back for handling exception during streaming.
     *
     * @param e thrown exception
     */
    void on_error();

    /**
     * Prepare this session for sending/receiving files.
     */
    void prepare(std::vector<stream_request> requests, std::vector<stream_summary> summaries);

    /**
     * Call back after sending FileMessageHeader.
     *
     * @param header sent header
     */
    void file_sent(const messages::file_message_header& header);

    /**
     * Call back after receiving FileMessageHeader.
     *
     * @param message received file
     */
    void receive(messages::incoming_file_message message);

    void progress(/* Descriptor desc */ progress_info::direction dir, long bytes, long total);

    void received(UUID cf_id, int sequence_number);

    /**
     * Call back on receiving {@code StreamMessage.Type.RETRY} message.
     *
     * @param cfId ColumnFamily ID
     * @param sequenceNumber Sequence number to indicate which file to stream again
     */
    void retry(UUID cf_id, int sequence_number);

    /**
     * Check if session is completed on receiving {@code StreamMessage.Type.COMPLETE} message.
     */
    void complete();

    /**
     * Call back on receiving {@code StreamMessage.Type.SESSION_FAILED} message.
     */
    void session_failed();

#if 0
    public void doRetry(FileMessageHeader header, Throwable e)
    {
        logger.warn("[Stream #{}] Retrying for following error", planId(), e);
        // retry
        retries++;
        if (retries > DatabaseDescriptor.getMaxStreamingRetries())
            onError(new IOException("Too many retries for " + header, e));
        else
            handler.sendMessage(new RetryMessage(header.cfId, header.sequenceNumber));
    }
#endif

    /**
     * @return Current snapshot of this session info.
     */
    session_info get_session_info();

    void task_completed(stream_receive_task& completed_task);

    void task_completed(stream_transfer_task& completed_task);

public:
    virtual void on_join(inet_address endpoint, endpoint_state ep_state) override {}
    virtual void before_change(inet_address endpoint, endpoint_state current_state, application_state new_state_key, versioned_value new_value) override {}
    virtual void on_change(inet_address endpoint, application_state state, versioned_value value) override {}
    virtual void on_alive(inet_address endpoint, endpoint_state state) override {}
    virtual void on_dead(inet_address endpoint, endpoint_state state) override {}
    virtual void on_remove(inet_address endpoint) override { close_session(stream_session_state::FAILED); }
    virtual void on_restart(inet_address endpoint, endpoint_state ep_state) override { close_session(stream_session_state::FAILED); }

private:
    bool maybe_completed();
#if 0

    /**
     * Flushes matching column families from the given keyspace, or all columnFamilies
     * if the cf list is empty.
     */
    private void flushSSTables(Iterable<ColumnFamilyStore> stores)
    {
        List<Future<?>> flushes = new ArrayList<>();
        for (ColumnFamilyStore cfs : stores)
            flushes.add(cfs.forceFlush());
        FBUtilities.waitOnFutures(flushes);
    }
#endif
    void prepare_receiving(stream_summary& summary);
    void start_streaming_files();
};

} // namespace streaming
<|endoftext|>


<commit_before>// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "config.h"
#include "modules/serviceworkers/WaitUntilObserver.h"

#include "bindings/v8/ScriptFunction.h"
#include "bindings/v8/ScriptPromise.h"
#include "bindings/v8/ScriptValue.h"
#include "core/dom/ExecutionContext.h"
#include "platform/NotImplemented.h"
#include "wtf/Assertions.h"
#include "wtf/RefCounted.h"
#include "wtf/RefPtr.h"

namespace WebCore {

class WaitUntilObserver::ThenFunction FINAL : public ScriptFunction {
public:
    enum ResolveType {
        Fulfilled,
        Rejected,
    };

    static PassOwnPtr<ScriptFunction> create(PassRefPtr<WaitUntilObserver> observer, ResolveType type)
    {
        return adoptPtr(new ThenFunction(toIsolate(observer->executionContext()), observer, type));
    }

private:
    ThenFunction(v8::Isolate* isolate, PassRefPtr<WaitUntilObserver> observer, ResolveType type)
        : ScriptFunction(isolate)
        , m_observer(observer)
        , m_resolveType(type)
    {
    }

    virtual ScriptValue call(ScriptValue value) OVERRIDE
    {
        ASSERT(m_observer);
        ASSERT(m_resolveType == Fulfilled || m_resolveType == Rejected);
        if (m_resolveType == Rejected)
            m_observer->reportError(value);
        m_observer->decrementPendingActivity();
        m_observer = 0;
        return value;
    }

    RefPtr<WaitUntilObserver> m_observer;
    ResolveType m_resolveType;
};

PassRefPtr<WaitUntilObserver> WaitUntilObserver::create(ExecutionContext* context, int eventID)
{
    return adoptRef(new WaitUntilObserver(context, eventID));
}

WaitUntilObserver::~WaitUntilObserver()
{
    ASSERT(!m_pendingActivity);
}

void WaitUntilObserver::willDispatchEvent()
{
    incrementPendingActivity();
}

void WaitUntilObserver::didDispatchEvent()
{
    decrementPendingActivity();
}

void WaitUntilObserver::waitUntil(const ScriptValue& value)
{
    incrementPendingActivity();
    ScriptPromise(value).then(
        ThenFunction::create(this, ThenFunction::Fulfilled),
        ThenFunction::create(this, ThenFunction::Rejected));
}

WaitUntilObserver::WaitUntilObserver(ExecutionContext* context, int eventID)
    : ContextLifecycleObserver(context)
    , m_eventID(eventID)
    , m_pendingActivity(0)
{
}

void WaitUntilObserver::reportError(const ScriptValue& value)
{
    // FIXME: Propagate error message to the client for onerror handling.
    notImplemented();
}

void WaitUntilObserver::incrementPendingActivity()
{
    ++m_pendingActivity;
}

void WaitUntilObserver::decrementPendingActivity()
{
    ASSERT(m_pendingActivity > 0);
    if (--m_pendingActivity || !executionContext())
        return;

    ServiceWorkerGlobalScopeClient::from(executionContext())->didHandleInstallEvent(m_eventID);
    observeContext(0);
}

} // namespace WebCore
<commit_msg>Possible crash fix in ServiceWorker's InstallEvent::waitUntil<commit_after>// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "config.h"
#include "modules/serviceworkers/WaitUntilObserver.h"

#include "bindings/v8/ScriptFunction.h"
#include "bindings/v8/ScriptPromise.h"
#include "bindings/v8/ScriptValue.h"
#include "core/dom/ExecutionContext.h"
#include "platform/NotImplemented.h"
#include "wtf/Assertions.h"
#include "wtf/RefCounted.h"
#include "wtf/RefPtr.h"

namespace WebCore {

class WaitUntilObserver::ThenFunction FINAL : public ScriptFunction {
public:
    enum ResolveType {
        Fulfilled,
        Rejected,
    };

    static PassOwnPtr<ScriptFunction> create(PassRefPtr<WaitUntilObserver> observer, ResolveType type)
    {
        ExecutionContext* executionContext = observer->executionContext();
        return adoptPtr(new ThenFunction(toIsolate(executionContext), observer, type));
    }

private:
    ThenFunction(v8::Isolate* isolate, PassRefPtr<WaitUntilObserver> observer, ResolveType type)
        : ScriptFunction(isolate)
        , m_observer(observer)
        , m_resolveType(type)
    {
    }

    virtual ScriptValue call(ScriptValue value) OVERRIDE
    {
        ASSERT(m_observer);
        ASSERT(m_resolveType == Fulfilled || m_resolveType == Rejected);
        if (m_resolveType == Rejected)
            m_observer->reportError(value);
        m_observer->decrementPendingActivity();
        m_observer = 0;
        return value;
    }

    RefPtr<WaitUntilObserver> m_observer;
    ResolveType m_resolveType;
};

PassRefPtr<WaitUntilObserver> WaitUntilObserver::create(ExecutionContext* context, int eventID)
{
    return adoptRef(new WaitUntilObserver(context, eventID));
}

WaitUntilObserver::~WaitUntilObserver()
{
    ASSERT(!m_pendingActivity);
}

void WaitUntilObserver::willDispatchEvent()
{
    incrementPendingActivity();
}

void WaitUntilObserver::didDispatchEvent()
{
    decrementPendingActivity();
}

void WaitUntilObserver::waitUntil(const ScriptValue& value)
{
    incrementPendingActivity();
    ScriptPromise(value).then(
        ThenFunction::create(this, ThenFunction::Fulfilled),
        ThenFunction::create(this, ThenFunction::Rejected));
}

WaitUntilObserver::WaitUntilObserver(ExecutionContext* context, int eventID)
    : ContextLifecycleObserver(context)
    , m_eventID(eventID)
    , m_pendingActivity(0)
{
}

void WaitUntilObserver::reportError(const ScriptValue& value)
{
    // FIXME: Propagate error message to the client for onerror handling.
    notImplemented();
}

void WaitUntilObserver::incrementPendingActivity()
{
    ++m_pendingActivity;
}

void WaitUntilObserver::decrementPendingActivity()
{
    ASSERT(m_pendingActivity > 0);
    if (--m_pendingActivity || !executionContext())
        return;

    ServiceWorkerGlobalScopeClient::from(executionContext())->didHandleInstallEvent(m_eventID);
    observeContext(0);
}

} // namespace WebCore
<|endoftext|>