text:
#ifndef pcw_Database_hpp__
#define pcw_Database_hpp__

#include "Tables.h"
#include "core/Book.hpp"
#include "core/BookBuilder.hpp"
#include "core/Line.hpp"
#include "core/LineBuilder.hpp"
#include "core/Page.hpp"
#include "core/PageBuilder.hpp"
#include "core/Project.hpp"
#include "core/ProjectBuilder.hpp"
#include <boost/optional.hpp>
#include <crow/logging.h>
#include <memory>
#include <sqlpp11/sqlpp11.h>

namespace pcw {
struct ProjectEntry;

namespace detail {
template <class Row> FileType to_file_type(const Row &row) {
  const auto ft = static_cast<int>(row.filetype);
  if (ft >= static_cast<int>(FileType::End)) {
    throw std::logic_error("invalid file type");
  }
  return static_cast<FileType>(ft);
}

template <class T, class F> void set_if_not_null(const T &t, F f) {
  if (not t.is_null())
    f(t);
}
template <class Row> BookData make_book_data(const Row &row) noexcept;

template <class Row> ProjectEntry make_project_entry(const Row &row) noexcept;

template <class Db>
void insert_pages_into_project_pages(Db &db, const Project &p);

template <class Db, class P, class Q, class R>
void insert_page(Db &db, P &p, Q &q, R &r, const Page &page);

template <class Db, class Q, class R>
void insert_line(Db &db, Q &q, R &r, const Line &line);

template <class Db, class R>
void insert_content(Db &db, R &r, const Line &line);

template <class Db> void insert_book_info_and_set_id(Db &db, Book &book);

template <class Db> void insert_project_info_and_set_id(Db &db, Project &view);

template <class Db> void delete_project(Db &db, int pid);

template <class Db> void delete_page(Db &db, int bid, int pid);

template <class Db> void delete_line(Db &db, int bid, int pid, int lid);

template <class Db>
void select_pages(Db &db, const BookBuilder &builder, int bookid);

template <class Db>
void select_lines(Db &db, const PageBuilder &builder, int bookid, int pageid);

template <class Db>
void select_contents(Db &db, const LineBuilder &builder, int bookid, int pageid,
                     int lineid);
} // namespace detail

template <class Db> ProjectSptr insert_project(Db &db, Project &book);

template <class Db> BookSptr insert_book(Db &db, Book &book);

template <class Db> void update_book(Db &db, int id, const BookData &data);

struct ProjectEntry {
  bool is_book() const noexcept { return this->origin == this->projectid; }
  int origin, owner, projectid, pages;
};

template <class Db>
boost::optional<ProjectEntry> select_project_entry(Db &db, int projectid);

template <class Db>
std::vector<ProjectEntry> select_all_project_entries(Db &db, int owner);

template <class Db>
boost::optional<BookData> select_book_data(Db &db, int bookid);

template <class Db>
std::vector<std::pair<BookData, ProjectEntry>> select_all_projects(Db &db,
                                                                   int userid);

template <class Db> void update_project_owner(Db &db, int projectid, int owner);

template <class Db> BookSptr select_book(Db &db, int owner, int bookid);

template <class Db>
ProjectSptr select_project(Db &db, const Book &book, int projectid);

template <class Db> void update_line(Db &db, const Line &line);
} // namespace pcw

////////////////////////////////////////////////////////////////////////////////
template <class Db>
void pcw::detail::insert_project_info_and_set_id(Db &db, Project &view) {
  using namespace sqlpp;
  tables::Projects projects;
  auto id = db(
      insert_into(projects).set(projects.origin = view.origin().id(),
                                projects.pages = static_cast<int>(view.size()),
                                projects.owner = view.owner()));
  view.set_id(id);
}

////////////////////////////////////////////////////////////////////////////////
template <class Db>
pcw::ProjectSptr pcw::insert_project(Db &db, Project &view) {
  detail::insert_project_info_and_set_id(db, view);
  detail::insert_pages_into_project_pages(db, view);
  return view.shared_from_this();
}

////////////////////////////////////////////////////////////////////////////////
template <class Db>
void pcw::detail::insert_pages_into_project_pages(Db &db, const Project &view) {
  using namespace sqlpp;
  tables::ProjectPages project_pages;
  auto stmnt = db.prepare(
      insert_into(project_pages)
          .set(project_pages.projectid = view.id(),
               project_pages.pageid = parameter(project_pages.pageid),
               project_pages.nextpageid = parameter(project_pages.nextpageid),
               project_pages.prevpageid = parameter(project_pages.prevpageid)));

  const auto e = view.end();
  boost::optional<int> prev;
  for (auto i = view.begin(); i != e;) {
    const auto id = (*i)->id();
    ++i;
    boost::optional<int> next;
    if (i != e) {
      next = (*i)->id();
    }
    stmnt.params.pageid = id;
    stmnt.params.nextpageid = next.value_or(id);
    stmnt.params.prevpageid = prev.value_or(id);
    db(stmnt);
    prev = id;
  }
}

////////////////////////////////////////////////////////////////////////////////
template <class Db>
void pcw::detail::insert_book_info_and_set_id(Db &db, Book &book) {
  using namespace sqlpp;
  tables::Projects projects;
  auto id = db(insert_into(projects).set(projects.origin = 0,
                                         projects.owner = book.owner(),
                                         projects.pages = book.size()));
  CROW_LOG_DEBUG << "(insert_book_info_and_set_id) id: " << id;
  book.set_id(id);
  db(update(projects).set(projects.origin = id).where(projects.id == id));
}

////////////////////////////////////////////////////////////////////////////////
template <class Db> pcw::BookSptr pcw::insert_book(Db &db, Book &book) {
  using namespace sqlpp;
  detail::insert_book_info_and_set_id(db, book);

  tables::Books books;
  auto stmnt = insert_into(books).set(
      books.author = book.data.author, books.title = book.data.title,
      books.directory = book.data.dir.string(), books.year = book.data.year,
      books.uri = book.data.uri, books.bookid = book.id(),
      books.description = book.data.description,
      books.profilerurl = book.data.profilerUrl,
      books.pooled = book.data.pooled,
      books.histpatterns = book.data.histPatterns, books.lang = book.data.lang);
  CROW_LOG_DEBUG << "(insert_book) bookid:      " << book.id();
  CROW_LOG_DEBUG << "(insert_book) author:      " << book.data.author;
  CROW_LOG_DEBUG << "(insert_book) title:       " << book.data.title;
  CROW_LOG_DEBUG << "(insert_book) directory:   " << book.data.dir;
  CROW_LOG_DEBUG << "(insert_book) year:        " << book.data.year;
  CROW_LOG_DEBUG << "(insert_book) uri:         " << book.data.author;
  CROW_LOG_DEBUG << "(insert_book) description: " << book.data.description;
  db(stmnt);

  tables::Pages pages;
  auto p = db.prepare(insert_into(pages).set(
      pages.bookid = parameter(pages.bookid),
      pages.pageid = parameter(pages.pageid),
      pages.imagepath = parameter(pages.imagepath),
      pages.ocrpath = parameter(pages.ocrpath),
      pages.filetype = parameter(pages.filetype),
      pages.pleft = parameter(pages.pleft), pages.ptop = parameter(pages.ptop),
      pages.pright = parameter(pages.pright),
      pages.pbottom = parameter(pages.pbottom)));

  tables::Textlines textlines;
  auto q = db.prepare(insert_into(textlines).set(
      textlines.bookid = parameter(textlines.bookid),
      textlines.pageid = parameter(textlines.pageid),
      textlines.lineid = parameter(textlines.lineid),
      textlines.imagepath = parameter(textlines.imagepath),
      textlines.lleft = parameter(textlines.lleft),
      textlines.ltop = parameter(textlines.ltop),
      textlines.lright = parameter(textlines.lright),
      textlines.lbottom = parameter(textlines.lbottom)));
  tables::Contents contents;
  auto r = db.prepare(
      insert_into(contents).set(contents.bookid = parameter(contents.bookid),
                                contents.pageid = parameter(contents.pageid),
                                contents.lineid = parameter(contents.lineid),
                                contents.seq = parameter(contents.seq),
                                contents.cid = parameter(contents.cid),
                                contents.ocr = parameter(contents.ocr),
                                contents.cor = parameter(contents.cor),
                                contents.cut = parameter(contents.cut),
                                contents.conf = parameter(contents.conf)));
  detail::insert_pages_into_project_pages(db, book);
  for (const auto &page : book) {
    assert(page);
    detail::insert_page(db, p, q, r, *page);
  }
  return std::static_pointer_cast<Book>(book.shared_from_this());
}

////////////////////////////////////////////////////////////////////////////////
template <class Db, class P, class Q, class R>
void pcw::detail::insert_page(Db &db, P &p, Q &q, R &r, const Page &page) {
  p.params.bookid = page.book().id();
  p.params.pageid = page.id();
  p.params.imagepath = page.img.string();
  p.params.ocrpath = page.ocr.string();
  p.params.filetype = static_cast<int>(page.file_type);
  p.params.pleft = page.box.left();
  p.params.ptop = page.box.top();
  p.params.pright = page.box.right();
  p.params.pbottom = page.box.bottom();
  CROW_LOG_DEBUG << "(insert_page) bookid:    " << page.book().id();
  CROW_LOG_DEBUG << "(insert_page) pageid:    " << page.id();
  CROW_LOG_DEBUG << "(insert_page) imagepath: " << page.img.string();
  CROW_LOG_DEBUG << "(insert_page) ocrpath:   " << page.ocr.string();
  // CROW_LOG_DEBUG << "(insert_page) pleft:     " << page.box.left();
  // CROW_LOG_DEBUG << "(insert_page) ptop:      " << page.box.top();
  // CROW_LOG_DEBUG << "(insert_page) pright:    " << page.box.right();
  // CROW_LOG_DEBUG << "(insert_page) pbottom:   " << page.box.bottom();
  db(p);
  for (const auto &line : page) {
    assert(line);
    detail::insert_line(db, q, r, *line);
  }
}

////////////////////////////////////////////////////////////////////////////////
template <class Db, class Q, class R>
void pcw::detail::insert_line(Db &db, Q &q, R &r, const Line &line) {
  q.params.bookid = line.page().book().id();
  q.params.pageid = line.page().id();
  q.params.lineid = line.id();
  q.params.imagepath = line.img.string();
  q.params.lleft = line.box.left();
  q.params.ltop = line.box.top();
  q.params.lright = line.box.right();
  q.params.lbottom = line.box.bottom();
  CROW_LOG_DEBUG << "(insert_line) bookid:    " << line.page().book().id();
  CROW_LOG_DEBUG << "(insert_line) pageid:    " << line.page().id();
  CROW_LOG_DEBUG << "(insert_line) lineid:    " << line.id();
  CROW_LOG_DEBUG << "(insert_line) imagepath: " << line.img.string();
  // CROW_LOG_DEBUG << "(insert_line) lleft:     " << line.box.left();
  // CROW_LOG_DEBUG << "(insert_line) ltop:      " << line.box.top();
  // CROW_LOG_DEBUG << "(insert_line) lright:    " << line.box.right();
  // CROW_LOG_DEBUG << "(insert_line) lbottom:   " << line.box.bottom();
  db(q);
  insert_content(db, r, line);
}

////////////////////////////////////////////////////////////////////////////////
template <class Db, class R>
void pcw::detail::insert_content(Db &db, R &r, const Line &line) {
  r.params.bookid = line.page().book().id();
  r.params.pageid = line.page().id();
  r.params.lineid = line.id();
  for (auto i = 0U; i < line.size(); ++i) {
    r.params.seq = i;
    r.params.cid = i;
    r.params.ocr = line[i].ocr;
    r.params.cor = line[i].cor;
    r.params.cut = line[i].cut;
    r.params.conf = line[i].conf;
    db(r);
  }
}

////////////////////////////////////////////////////////////////////////////////
template <class Db>
void pcw::update_book(Db &db, int id, const BookData &data) {
  using namespace sqlpp;
  tables::Books books;
  db(update(books)
         .set(books.author = data.author, books.title = data.title,
              books.directory = data.dir.string(), books.year = data.year,
              books.uri = data.uri, books.description = data.description,
              books.profilerurl = data.profilerUrl,
              books.histpatterns = data.histPatterns,
              books.pooled = data.pooled, books.profiled = data.profiled,
              books.extendedlexicon = data.extendedLexicon,
              books.postcorrected = data.postCorrected, books.lang = data.lang)
         .where(books.bookid == id));
}

////////////////////////////////////////////////////////////////////////////////
template <class Db>
boost::optional<pcw::ProjectEntry> pcw::select_project_entry(Db &db,
                                                             int projectid) {
  using namespace sqlpp;
  tables::Projects projects;
  auto stmnt =
      select(all_of(projects)).from(projects).where(projects.id == projectid);
  auto res = db(stmnt);
  if (not res.empty())
    return detail::make_project_entry(res.front());
  return {};
}

////////////////////////////////////////////////////////////////////////////////
template <class Db>
std::vector<std::pair<pcw::BookData, pcw::ProjectEntry>>
pcw::select_all_projects(Db &db, int userid) {
  using namespace sqlpp;
  tables::Projects projects;
  tables::Books books;
  auto stmnt =
      select(all_of(projects), all_of(books))
          .from(books.join(projects).on(books.bookid == projects.origin))
          .where(projects.owner == userid);
  std::vector<std::pair<BookData, ProjectEntry>> data;
  for (const auto &row : db(stmnt)) {
    const auto bookdata = detail::make_book_data(row);
    const auto projectentry = detail::make_project_entry(row);
    data.emplace_back(bookdata, projectentry);
  }
  return data;
}

////////////////////////////////////////////////////////////////////////////////
template <class Row>
pcw::ProjectEntry pcw::detail::make_project_entry(const Row &row) noexcept {
  ProjectEntry entry;
  set_if_not_null(row.id, [&](const auto pid) {
    return entry.projectid = static_cast<int>(pid);
  });
  set_if_not_null(row.owner, [&](const auto owner) {
    return entry.owner = static_cast<int>(owner);
  });
  set_if_not_null(row.origin, [&](const auto origin) {
    return entry.origin = static_cast<int>(origin);
  });
  set_if_not_null(row.pages, [&](const auto pages) {
    return entry.pages = static_cast<int>(pages);
  });
  return entry;
}

////////////////////////////////////////////////////////////////////////////////
template <class Row>
pcw::BookData pcw::detail::make_book_data(const Row &row) noexcept {
  BookData data;
  detail::set_if_not_null(row.description,
                          [&](const auto &d) { data.description = d; });
  detail::set_if_not_null(row.histpatterns,
                          [&](const auto &ps) { data.histPatterns = ps; });
  detail::set_if_not_null(row.uri, [&](const auto &u) { data.uri = u; });
  detail::set_if_not_null(row.year, [&](const auto &y) { data.year = y; });
  detail::set_if_not_null(row.author, [&](const auto &a) { data.author = a; });
  detail::set_if_not_null(row.title, [&](const auto &t) { data.title = t; });
  detail::set_if_not_null(row.lang, [&](const auto &l) { data.lang = l; });
  detail::set_if_not_null(row.directory, [&](const auto &d) { data.dir = d; });
  detail::set_if_not_null(row.pooled, [&](const auto &t) { data.pooled = t; });
  detail::set_if_not_null(row.profiled,
                          [&](const auto &t) { data.profiled = t; });
  detail::set_if_not_null(row.extendedlexicon,
                          [&](const auto &t) { data.extendedLexicon = t; });
  detail::set_if_not_null(row.postcorrected,
                          [&](const auto &t) { data.postCorrected = t; });
  detail::set_if_not_null(row.profilerurl,
                          [&](const auto &u) { data.profilerUrl = u; });
  return data;
}

////////////////////////////////////////////////////////////////////////////////
template <class Db>
boost::optional<pcw::BookData> pcw::select_book_data(Db &db, int bookid) {
  tables::Projects p;
  tables::Books b;
  auto stmnt = select(all_of(b))
                   .from(b.join(p).on(b.bookid == p.origin))
                   .where(b.bookid == bookid);
  auto res = db(stmnt);
  if (not res.empty())
    return detail::make_book_data(res.front());
  return {};
}

////////////////////////////////////////////////////////////////////////////////
template <class Db>
void pcw::update_project_owner(Db &db, int projectid, int owner) {
  using namespace sqlpp;
  tables::Projects projects;
  auto stmnt = update(projects)
                   .set(projects.owner = owner)
                   .where(projects.id == projectid);
  db(stmnt);
}

////////////////////////////////////////////////////////////////////////////////
template <class Db>
pcw::BookSptr pcw::select_book(Db &db, int owner, int bookid) {
  auto book_data = select_book_data(db, bookid);
  if (not book_data)
    return nullptr;
  BookBuilder builder;
  builder.set_id(bookid);
  builder.set_book_data(*book_data);
  builder.set_owner(owner);
  detail::select_pages(db, builder, bookid);
  return builder.build();
}

////////////////////////////////////////////////////////////////////////////////
template <class Db>
void pcw::detail::select_pages(Db &db, const BookBuilder &builder, int bookid) {
  using namespace sqlpp;
  tables::Pages pages;
  auto stmnt = select(all_of(pages)).from(pages).where(pages.bookid == bookid);
  PageBuilder pbuilder;
  for (const auto &row : db(stmnt)) {
    pbuilder.reset();
    detail::set_if_not_null(row.imagepath, [&](const auto &p) {
      pbuilder.set_image_path(Path(p));
    });
    detail::set_if_not_null(
        row.ocrpath, [&](const auto &p) { pbuilder.set_ocr_path(Path(p)); });
    pbuilder.set_box({static_cast<int>(row.pleft), static_cast<int>(row.ptop),
                      static_cast<int>(row.pright),
                      static_cast<int>(row.pbottom)});
    pbuilder.set_id(row.pageid);
    pbuilder.set_file_type(detail::to_file_type(row));
    detail::select_lines(db, pbuilder, bookid, row.pageid);
    builder.append(*pbuilder.build());
  }
}

////////////////////////////////////////////////////////////////////////////////
template <class Db>
void pcw::detail::select_lines(Db &db, const PageBuilder &builder, int bookid,
                               int pageid) {
  using namespace sqlpp;
  tables::Textlines lines;
  auto stmnt = select(all_of(lines))
                   .from(lines)
                   .where(lines.bookid == bookid and lines.pageid == pageid)
                   .order_by(lines.lineid.asc());
  LineBuilder lbuilder;
  for (const auto &row : db(stmnt)) {
    lbuilder.reset();
    detail::set_if_not_null(row.imagepath, [&](const auto &p) {
      lbuilder.set_image_path(Path(p));
    });
    lbuilder.set_box({static_cast<int>(row.lleft), static_cast<int>(row.ltop),
                      static_cast<int>(row.lright),
                      static_cast<int>(row.lbottom)});
    lbuilder.set_id(row.lineid);
    detail::select_contents(db, lbuilder, bookid, pageid, row.lineid);
    builder.append(*lbuilder.build());
  }
}

////////////////////////////////////////////////////////////////////////////////
template <class Db>
void pcw::detail::select_contents(Db &db, const LineBuilder &builder,
                                  int bookid, int pageid, int lineid) {
  using namespace sqlpp;
  tables::Contents contents;
  auto stmnt =
      select(all_of(contents))
          .from(contents)
          .where(contents.bookid == bookid and contents.pageid == pageid and
                 contents.lineid == lineid)
          .order_by(contents.seq.asc());
  for (const auto &row : db(stmnt)) {
    builder.append(static_cast<wchar_t>(row.ocr), static_cast<wchar_t>(row.cor),
                   row.cut, row.conf);
  }
}

////////////////////////////////////////////////////////////////////////////////
template <class Db>
pcw::ProjectSptr pcw::select_project(Db &db, const Book &book, int projectid) {
  using namespace sqlpp;
  tables::ProjectPages project_pages;
  auto stmnt = select(project_pages.pageid)
                   .from(project_pages)
                   .where(project_pages.projectid == projectid);
  ProjectBuilder builder;
  builder.set_origin(book);
  builder.set_project_id(projectid);
  for (const auto &row : db(stmnt)) {
    builder.add_page(row.pageid);
  }
  auto p = builder.build();
  CROW_LOG_DEBUG << "(select_project) project id: " << p->id()
                 << " origin: " << p->origin().id() << " size: " << p->size();
  return p;
}

////////////////////////////////////////////////////////////////////////////////
template <class Db> void pcw::update_line(Db &db, const Line &line) {
  using namespace sqlpp;
  tables::Contents contents;
  auto remove = remove_from(contents).where(
      contents.bookid == line.page().book().id() and
      contents.pageid == line.page().id() and contents.lineid == line.id());
  auto insert = db.prepare(
      insert_into(contents).set(contents.bookid = parameter(contents.bookid),
                                contents.pageid = parameter(contents.pageid),
                                contents.lineid = parameter(contents.lineid),
                                contents.seq = parameter(contents.seq),
                                contents.ocr = parameter(contents.ocr),
                                contents.cor = parameter(contents.cor),
                                contents.cut = parameter(contents.cut),
                                contents.conf = parameter(contents.conf)));
  db.run(remove);
  detail::insert_content(db, insert, line);
}

////////////////////////////////////////////////////////////////////////////////
template <class Db> void delete_project(Db &db, int pid) {
  using namespace sqlpp;
  tables::Books b;
  tables::Projects p;
  tables::ProjectPages pp;
  tables::Profiles ppp;
  tables::Pages pages;
  tables::Suggestions s;
  tables::Errorpatterns e;
  tables::Adaptivetokens a;
  tables::Textlines l;
  tables::Contents c;
  tables::Autocorrections ac;
  tables::Typcounts tc;
  tables::Jobs j;
  db(remove_from(pp).where(pp.projectid == pid));
  db(remove_from(ppp).where(ppp.bookid == pid));
  db(remove_from(pages).where(pages.bookid == pid));
  db(remove_from(a).where(a.bookid == pid));
  db(remove_from(l).where(l.bookid == pid));
  db(remove_from(c).where(c.bookid == pid));
  db(remove_from(e).where(e.bookid == pid));
  db(remove_from(s).where(s.bookid == pid));
  db(remove_from(ac).where(ac.bookid == pid));
  db(remove_from(tc).where(tc.bookid == pid));
  db(remove_from(j).where(j.id == pid));
  db(remove_from(b).where(b.bookid == pid));
  db(remove_from(p).where(p.id == pid));
}

////////////////////////////////////////////////////////////////////////////////
template <class Db> void delete_page(Db &db, int bid, int pid) {
  using namespace sqlpp;
  tables::ProjectPages pp;
  tables::Pages ps;
  tables::Textlines tl;
  tables::Contents c;
  db(remove_from(c).where(c.bookid == bid and c.pageid == pid));
  db(remove_from(tl).where(tl.bookid == bid and tl.pageid == pid));
  db(remove_from(ps).where(ps.bookid == bid and ps.pageid == pid));
  db(remove_from(pp).where(pp.projectid == bid and pp.pageid == pid));
}

////////////////////////////////////////////////////////////////////////////////
template <class Db> void delete_line(Db &db, int bid, int pid, int lid) {
  using namespace sqlpp;
  tables::Textlines tl;
  tables::Contents c;
  db(remove_from(c).where(c.bookid == bid and c.pageid == pid and
                          c.lineid == lid));
  db(remove_from(tl).where(tl.bookid == bid and tl.pageid == pid and
                           tl.lineid == lid));
}

#endif // pcw_Database_hpp__

max_stars_repo_name: cisocrgroup/pocoweb

max_issues_repo_name: cisocrgroup/pocoweb

max_forks_repo_name: cisocrgroup/pocoweb


text:
#ifndef CurveNormalization_hpp
#define CurveNormalization_hpp

#include <QAlgorithm.hpp>
#include <UMF/Evaluate1D.hpp>
#include <armadillo>
#include <alglib/integration.h>

namespace UMF {
	class CurveNormalization;
}

class UMF::CurveNormalization : public QAlgorithm {

	Q_OBJECT

	QA_INPUT(QVector<double>, Coefficients)
	QA_PARAMETER(double, LeftExtremum, 0.0)
	QA_PARAMETER(double, RightExtremum, 1.0)
	QA_OUTPUT(QVector<double>, Coefficients)

	QA_CTOR_INHERIT
	QA_IMPL_CREATE(CurveNormalization)

public:
	void run();
};

#endif /* CurveNormalization_hpp */

ext: hpp

max_stars_repo_name: DottD/audioRec

max_issues_repo_name: DottD/audioRec

max_forks_repo_name: DottD/audioRec


text:
/*
 * Copyright (c) 2015, 2016, Yutaka Tsutano
 * Copyright (c) 2019, Mohannad Alhanahnah
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
 * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 * PERFORMANCE OF THIS SOFTWARE.
 */

#include <iostream>
#include <vector>
#include <thread>
#include <fstream>
#include <algorithm>

#include <boost/asio.hpp>
#include <boost/algorithm/string/predicate.hpp>

#include <jitana/jitana.hpp>
#include <jitana/util/jdwp.hpp>
#include <jitana/analysis/call_graph.hpp>
#include <jitana/analysis/def_use.hpp>

/* Begin ReAna */
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/depth_first_search.hpp>
#include "jitana/vm_core/hdl.hpp"
/* End ReAna */

/*DINA*/
#include <jitana/mpi/mpi.hpp>
#include <boost/algorithm/string/iter_find.hpp>
#include <boost/algorithm/string.hpp>
#include <stdlib.h>
/*DINA*/

#include <unistd.h>
#include <sys/wait.h>

#ifdef __APPLE__
#include <OpenGL/gl.h>
#include <GLUT/glut.h>
#else
#include <GL/gl.h>
#include <GL/glut.h>
#endif

/*
 The format of method handler
 (classLoader)_(dex_num)_(method_num)
 set 2nd argument in the find method function should be set to true
 in order to load the method

 to get className
 m.methods()[s_v].jvm_hdl.type_hdl.descriptor
 */

std::vector< std::vector<jitana::dex_method_hdl> > mh_ref_pair;

struct insn_counter {
    long long counter = 0;
    long long delta = 0;
    long long last_accessed = 0;
    boost::optional<
    std::pair<jitana::method_vertex_descriptor,
    jitana::insn_vertex_descriptor>> vertices;
};

struct dex_file {
    std::string apk_filename;
    std::string odex_filename;
    std::unordered_map<uint32_t, insn_counter> counters;
    boost::optional<jitana::dex_file_hdl> hdl;
    //jitana::dex_file_hdl hdl;
};

std::vector<dex_file> dex_files;

static bool periodic_output = false;
static bool should_terminate = false;

static jitana::virtual_machine vm;
static jitana::class_loader_hdl system_loader_hdl = 0;
static jitana::class_loader_hdl app_loader_hdl = 1;

/* Begin ReAna */
struct ref_method {
    uint32_t methodIndex;
    std::string methodName;
    std::string className;
    std::string dexName;
    std::string cacheName;
    uint32_t insn_offset;
    jitana::dex_file_hdl hdl;
};
static std::vector<std::pair<ref_method, ref_method> > vRef;
static std::pair<ref_method, ref_method> refM;
static std::vector<std::pair<ref_method, ref_method> > already_written_ref;
static std::vector<std::pair<ref_method, ref_method> > printed_ref;
static std::vector<std::pair<std::string, jitana::dex_file_hdl> > file_name_hdl;
/* End ReAna */

/*DINA*/
int ref_flag = 0;
std::string ref_class_name;
std::string appPkgName;
std::set<std::string> found_intents; /*records all intents matching intents in the intent graph*/
std::vector<std::vector<std::string>> intent_filter_csvV;
std::vector<std::vector<std::string>> detailed_report_csvV;

jitana::jvm_method_hdl send_bc1 = { { 0, "Landroid/content/Context;" },
    "sendBroadcast(Landroid/content/Intent;)V" };
jitana::jvm_method_hdl send_bc2 = { { 0, "Landroid/content/Context;" },
    "sendBroadcast(Landroid/content/Intent;Ljava/lang/String;)V" };
jitana::jvm_method_hdl send_ordered_bc1 = { { 0, "Landroid/content/Context;" },
    "sendOrderedBroadcast(Landroid/content/Intent;Ljava/lang/String;ILandroid/content/BroadcastReceiver;Landroid/os/Handler;ILjava/lang/String;Landroid/os/Bundle;)V" };
jitana::jvm_method_hdl send_ordered_bc2 = { { 0, "Landroid/content/Context;" },
    "sendOrderedBroadcast(Landroid/content/Intent;Ljava/lang/String;)V" };
jitana::jvm_method_hdl send_sticky_bc = { { 0, "Landroid/content/Context;" },
    "sendStickyBroadcast(Landroid/content/Intent;)V" };
jitana::jvm_method_hdl send_sticky_ordered_bc = { { 0, "Landroid/content/Context;" },
    "sendStickyOrderedBroadcast(Landroid/content/Intent;Landroid/content/BroadcastReceiver;Landroid/os/Handler;ILjava/lang/String;Landroid/os/Bundle;)V" };

jitana::jvm_method_hdl start_activity = { { 0, "Landroid/content/Context;" },
    "startActivity(Landroid/content/Intent;)V" };
jitana::jvm_method_hdl start_activity_for_result = { { 0, "Landroid/content/Context;" },
    "startActivityForResult(Landroid/content/Intent;I)V" };

jitana::jvm_method_hdl start_service = { { 0, "Landroid/content/Context;" },
    "startService(Landroid/content/Intent;)Landroid/content/ComponentName;" };
jitana::jvm_method_hdl bind_service = { { 0, "Landroid/content/Context;" },
    "bindService(Landroid/content/Intent;Landroid/content/ServiceConnection;I)Z" };
/*DINA*/

// Lighting parameters.
static constexpr GLfloat light0_position[] = { 500.0f, 200.0f, 500.0f, 1.0f };
static constexpr GLfloat light0_ambient_color[] = { 0.5f, 0.5f, 0.5f, 1.0f };
static constexpr GLfloat light0_diffuse_color[] = { 0.8f, 0.8f, 0.8f, 1.0f };

constexpr int line_length = 128;

static int width = 0.0;
static int height = 0.0;
static int window_x = 100;
static int window_y = 100;
static int window_width = 1024;
static int window_height = 700;
static std::string title = "Jitana-TraVis";
static int window;

static double view_angle = -M_PI / 3.0 + M_PI / 2.0;
static double view_altitude = 0.5;
static double view_angle_offset = 0.0;
static double view_altitude_offset = 0.0;
static double view_center_x = 128.0;
static double view_center_x_offset = 0.0;
static double view_center_y = -line_length * 2.0;
static double view_center_y_offset = 0.0;
static double view_zoom = 0.17 * line_length / 128.0;
static double view_zoom_offset = 0.0;

static int drag_start_x = 0;
static int drag_start_y = 0;
static bool dragging = false;
static bool zooming = false;
static bool shifting = false;
static bool full_screen = false;

static void init_opengl();
static void reshape(int width, int height);
static void display();
static void handle_mouse_event(int button, int state, int x, int y);
static void handle_motion_event(int x, int y);
static void handle_keyboard_event(unsigned char c, int x, int y);
static void update_graphs();

void draw_instruction(int index, uint32_t /*address*/,
                      const insn_counter& counter) {
    float x = 14.0f * (index / line_length);
    float y = 4.0f * (index % line_length);
    float z = 0.2;

    // Draw a Red 1x1 Square centered at origin
    glBegin(GL_QUADS);
    {
        if (counter.counter > 0) {
            auto r = 0.8f * std::min(counter.counter + 1, 1000ll) / 1000.0f
            + 0.2f;
            auto d = 0.8f * std::min(counter.delta, 5ll) / 5.0f + 0.2f;
            // glColor3f(d, 0.2f, r);
            z += std::min(counter.counter + 1, 1000ll) / 400.0f + 1.0f;

            GLfloat color[] = { d, 0.2f, r, 1.0f };
            glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, color);
        } else {
            // glColor3f(0.2f, 0.2f, 0.2f);
            // glColor3f(1.0f, 1.0f, 0.2f);

            GLfloat color[] = { 1.0f, 1.0f, 0.2f, 1.0f };
            glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, color);
        }
        constexpr auto w = 10.0f;
        constexpr auto h = 2.0f;

        glNormal3f(0, 1, 0);
        glVertex3f(x + w / 2, z, y + h / 2);
        glVertex3f(x - w / 2, z, y + h / 2);
        glVertex3f(x - w / 2, z, y - h / 2);
        glVertex3f(x + w / 2, z, y - h / 2);

        glNormal3f(0, 0, 1);
        glVertex3f(x + w / 2, z, y + h / 2);
        glVertex3f(x - w / 2, z, y + h / 2);
        glVertex3f(x - w / 2, 0, y + h / 2);
        glVertex3f(x + w / 2, 0, y + h / 2);

        glNormal3f(0, 0, -1);
        glVertex3f(x + w / 2, z, y - h / 2);
        glVertex3f(x - w / 2, z, y - h / 2);
        glVertex3f(x - w / 2, 0, y - h / 2);
        glVertex3f(x + w / 2, 0, y - h / 2);

        glNormal3f(1, 0, 0);
        glVertex3f(x + w / 2, z, y + h / 2);
        glVertex3f(x + w / 2, z, y - h / 2);
        glVertex3f(x + w / 2, 0, y - h / 2);
        glVertex3f(x + w / 2, 0, y + h / 2);

        glNormal3f(-1, 0, 0);
        glVertex3f(x - w / 2, z, y + h / 2);
        glVertex3f(x - w / 2, z, y - h / 2);
        glVertex3f(x - w / 2, 0, y - h / 2);
        glVertex3f(x - w / 2, 0, y + h / 2);
    }
    glEnd();
}

void init_opengl() {
    // Set the clear color.
    constexpr GLfloat clearColor[] = { 0.0, 0.0, 0.0, 1.0 };
    glClearColor(clearColor[0], clearColor[1], clearColor[2], clearColor[3]);

    // Set the lights.
    glEnable(GL_LIGHT0);
    glLightfv(GL_LIGHT0, GL_POSITION, light0_position);
    glLightfv(GL_LIGHT0, GL_AMBIENT, light0_ambient_color);
    glLightfv(GL_LIGHT0, GL_DIFFUSE, light0_diffuse_color);

    // Set the shade model.
    glShadeModel(GL_SMOOTH);

    // Enable lighting.
    glEnable(GL_LIGHTING);

    // Enable automatic normalization after transformations.
    glEnable(GL_NORMALIZE);

    // Enable antialiasing.
    glEnable(GL_POLYGON_SMOOTH);
}

void display() {
    // Clear the screen.
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    // Enable the depth buffer.
    glEnable(GL_DEPTH_TEST);

    // Compute the view matrix.
    {
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();
        auto angle = view_angle + view_angle_offset;
        auto altitude = std::max(view_altitude + view_altitude_offset, 0.0);
        gluLookAt(1000.0 * cos(angle) + view_center_x + view_center_x_offset,
                  1000.0 * altitude,
                  1000.0 * sin(angle) - (view_center_y + view_center_y_offset),
                  view_center_x + view_center_x_offset, 0,
                  -(view_center_y + view_center_y_offset), 0.0, 1.0, 0.0);
    }

    int i = 0;
    for (auto& dex : dex_files) {
        glPushMatrix();
        {
            // Disable lighting.
            glDisable(GL_LIGHTING);

            float x = 14.0f * (i / line_length);
            float y = 4.0f * (i % line_length);
            glColor3f(1.0f, 1.0f, 1.0f);
            glRasterPos3d(x, 3.0, y - 4.0);
            for (const auto& c : dex.apk_filename) {
                glutBitmapCharacter(GLUT_BITMAP_HELVETICA_12, c);
            }

            // Enable lighting.
            glEnable(GL_LIGHTING);
        }
        glPopMatrix();

        // Draw the instructions.
        const auto& cg = vm.classes();
        const auto& mg = vm.methods();
        for (const auto& cv : boost::make_iterator_range(vertices(cg))) {
            // Ignore a class implemented in a different DEX file.
            if (cg[cv].hdl.file_hdl != *dex.hdl) {
                continue;
            }

            auto draw_method = [&](jitana::method_vertex_descriptor mv) {
                const auto& ig = mg[mv].insns;
                auto insns_off = ig[boost::graph_bundle].insns_off;
                if (insns_off == 0) {
                    return;
                }

                // A method should be defined in the same class.
                if (mg[mv].class_hdl != cg[cv].hdl) {
                    return;
                }

                for (const auto& iv :
                     boost::make_iterator_range(vertices(ig))) {
                    if (!is_basic_block_head(iv, ig)) {
                        continue;
                    }

                    auto addr = insns_off + ig[iv].off * 2;
                    draw_instruction(i++, addr, dex.counters[addr]);

                    // Checking
                    auto p = vm.find_insn(*dex.hdl, addr, false);
                    if (!p) {
                        std::cerr << "method=" << mg[mv].hdl << " ";
                        std::cerr << "insns_off=" << insns_off << " ";
                        std::cerr << "ig[iv].off=" << ig[iv].off << " ";
                        std::cerr << ig[iv].insn << " " << addr << "\n";
                    }
                    else {
                        if (mg[mv].hdl != mg[p->first].hdl) {
                            std::cerr << "************* Bad! ";
                            std::cerr << "method=" << mg[mv].hdl << " ";
                            std::cerr << "ig[iv].off=" << ig[iv].off << " ";
                            std::cerr << "found_method=" << p->first << " ";
                            std::cerr << "found_insn=" << p->second << "\n";
                        }
                    }
                }
            };

            for (const auto& mh : cg[cv].vtable) {
                auto mv = vm.find_method(mh, false);
                if (mv) {
                    draw_method(*mv);
                }
            }

            for (const auto& mh : cg[cv].dtable) {
                auto mv = vm.find_method(mh, false);
                if (mv) {
                    draw_method(*mv);
                }
            }
        }

        i += line_length * 4;
        i -= (i % line_length);
    }

    // Update the screen by swapping the buffers.
    glutSwapBuffers();
}

static void handle_mouse_event(int button, int state, int x, int y) {
    switch (state) {
        case GLUT_DOWN:
            drag_start_x = x;
            drag_start_y = y;
            if (glutGetModifiers() == GLUT_ACTIVE_SHIFT) {
                shifting = true;
            } else {
                if (button == GLUT_RIGHT_BUTTON) {
                    zooming = true;
                } else {
                    dragging = true;
                }
            }
            break;
        case GLUT_UP:
            if (dragging) {
                view_angle += view_angle_offset;
                view_altitude += view_altitude_offset;
                view_altitude = std::max(view_altitude, 0.0);
                dragging = false;
            } else if (shifting) {
                view_center_x += view_center_x_offset;
                view_center_y += view_center_y_offset;
                view_center_x_offset = 0.0;
                view_center_y_offset = 0.0;
                shifting = false;
                reshape(width, height);
            } else if (zooming) {
                view_zoom += view_zoom_offset;
                view_zoom = std::min(std::max(view_zoom, 0.01), 10000.0);
                zooming = false;
            }
            break;
    }
    view_angle_offset = 0.0;
    view_altitude_offset = 0.0;
    view_zoom_offset = 0.0;

    glutPostRedisplay();
}

static void handle_motion_event(int x, int y) {
    if (dragging) {
        view_angle_offset = 4.0 * (x - drag_start_x) / width;
        view_altitude_offset = 4.0 * (y - drag_start_y) / height;
        glutPostRedisplay();
    }

    if (zooming) {
        view_zoom_offset = static_cast<double>(y - drag_start_y) / height;
        reshape(width, height);
        glutPostRedisplay();
    }

    if (shifting) {
        const double a = -2000 * view_zoom * (x - drag_start_x) / width;
        const double b = -2000 * view_zoom * (y - drag_start_y) / height;
        view_center_x_offset = a * std::sin(view_angle)
        + b * std::cos(view_angle);
        view_center_y_offset = a * std::cos(view_angle)
        - b * std::sin(view_angle);
        reshape(width, height);
        glutPostRedisplay();
    }
}

static void update_graphs() {
    for (auto& dex : dex_files) {
        if (!dex.hdl) {
            continue;
        }

        for (auto& c : dex.counters) {
            auto& offset = c.first;
            auto& ictr = c.second;
            auto& vertices = ictr.vertices;
            if (!vertices) {
                vertices = vm.find_insn(*dex.hdl, offset, true);
            }
            if (vertices) {
                vm.methods()[vertices->first].insns[vertices->second].counter =
                ictr.counter;
            } else {
                std::cerr << "failed to find the vertex: ";
                std::cerr << *dex.hdl << " " << offset << "\n";
            }
        }
    }
}

static void handle_keyboard_event(unsigned char c, int /*x*/, int /*y*/) {
    switch (c) {
        case 'a':
        case 'A':
            std::cout << "loading all classes... " << std::flush;
            vm.load_all_classes(app_loader_hdl);
            std::cout << " done." << std::endl;
            break;
        case 'f':
        case 'F':
            if (full_screen) {
                glutPositionWindow(window_x, window_y);
                glutReshapeWindow(window_width, window_height);
                full_screen = false;
            } else {
                window_x = glutGet(GLUT_WINDOW_X);
                window_y = glutGet(GLUT_WINDOW_Y);
                window_width = glutGet(GLUT_WINDOW_WIDTH);
                window_height = glutGet(GLUT_WINDOW_HEIGHT);
                glutFullScreen();
                full_screen = true;
            }
            break;
        case 'g':
        case 'G':
            update_graphs();
            break;
        case 'p':
        case 'P':
            periodic_output = !periodic_output;
            std::cout << "periodic_output = " << periodic_output << "\n";
            break;
        case 'd':
        case 'D':
            // Compute the def-use edges.
            std::for_each(vertices(vm.methods()).first,
                          vertices(vm.methods()).second,
                          [&](const jitana::method_vertex_descriptor & v) {
                              add_def_use_edges(vm.methods()[v].insns);
                          });
            break;
    }
    glutPostRedisplay();
}

static void reshape(int width, int height) {
    ::width = width;
    ::height = height;

    // Compute the aspect ratio.
    const double aspectRatio = static_cast<double>(width) / height;

    // Compute the projection matrix.
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    double z = std::min(std::max(view_zoom + view_zoom_offset, 0.01), 10000.0);
    glOrtho(-1000.0 * aspectRatio * z, 1000.0 * aspectRatio * z, -1000.0 * z,
            1000.0 * z, -1400.0, 10000.0);

    // Set the viewport.
    glViewport(0, 0, width, height);
}

void pull_apk_files() {
    pid_t pid = ::fork();
    if (pid == 0) {
        // Run the shell script.
        ::execl("pull-apks", "pull-apks", nullptr);
        std::cout << "Command executed successfully\n";
    } else if (pid > 0) {
        int status = 0;
        ::waitpid(pid, &status, 0);
    } else {
        throw std::runtime_error("failed to pull APK files");
    }
}

std::string make_local_filename(const std::string& apk_filename) {
    if (apk_filename.size() < 2 || apk_filename[0] != '/') {
        throw std::invalid_argument("invalid APK file name");
    }

    std::string filename = "apks-extracted/";
    std::replace_copy(begin(apk_filename) + 1, end(apk_filename),
                      std::back_inserter(filename), '/', '@');
    if (!boost::ends_with(apk_filename, ".dex")) {
        filename += "/classes.dex";
    }
    return filename;
}

void update_insn_counters() {
    struct insn_counter_updater {
        std::vector<dex_file>::iterator it;

        void enter_dex_file(const std::string& apk_filename,
                            const std::string& odex_filename) {
            //Travis code
            it = std::find_if(begin(dex_files), end(dex_files),
                              [&](const auto & x) {
                                  return x.apk_filename == apk_filename;
                              });
            if (it == end(dex_files)) {
                dex_files.emplace_back();
                it = end(dex_files);
                --it;

                it->apk_filename = apk_filename;
                it->odex_filename = odex_filename;
            }

            /* Start ReAna */
            std::pair<std::string, jitana::dex_file_hdl> file_name_hdl_pair;
            file_name_hdl_pair.first = odex_filename;
            file_name_hdl_pair.second = *(it->hdl);
            file_name_hdl.push_back(file_name_hdl_pair);
            /* End ReAna */

            for (auto& c : it->counters) {
                c.second.delta = 0;
                ++c.second.last_accessed;
            }
        }

        void insn(uint32_t offset, uint16_t counter) {
            auto& c = it->counters[offset];
            c.counter += counter;
            c.delta = counter;
            c.last_accessed = 0;
        }
        void exit_dex_file() {
        }
    } updater;

    size_t dex_files_size_old = dex_files.size();

    jitana::jdwp_connection conn;
    conn.connect("localhost", "6100");
    conn.receive_insn_counters(updater);
    conn.close();

    if (dex_files_size_old != dex_files.size()) {
        pull_apk_files();
        for (auto& dex : dex_files) {
            if (dex.hdl) {
                continue;
            }

            std::string local_filename = make_local_filename(dex.apk_filename);

            auto lv = find_loader_vertex(app_loader_hdl, vm.loaders());
            if (!lv) {
                throw std::runtime_error("application loader not found");
            }

            dex.hdl = vm.loaders()[*lv].loader.add_file(local_filename);

            std::cout << "New DEX file (" << *dex.hdl << ") is added:\n";
            std::cout << "    Original: " << dex.apk_filename << "\n";
            std::cout << "    ODEX:     " << dex.odex_filename << "\n";
            std::cout << "    Local:    " << local_filename << "\n";

            std::ifstream pkg("output/pkgName.txt");
            std::string pkgName,line;
            while (std::getline(pkg,line))
                pkgName = line;

            std::ofstream ofs("output/output-reana/"+pkgName+"_dex.txt",std::ofstream::app);
            ofs << local_filename<<"\n";
        }
    }
}

void on_sigint(int) {
    std::cout << "\nInterrupted. Terminating the program..." << std::endl;
    should_terminate = true;
}

/* Start ReAna */
int add_reflection_edge(std::pair<ref_method, ref_method> &source_sink) {

    std::ofstream ofs;
    std::ifstream ofs_check("output/output-reana/ref_methods_pair.csv");
    std::vector<jitana::dex_method_hdl> v = std::vector<jitana::dex_method_hdl>(2);
    std::vector<bool> dup_flag;

    int isValidSource = 0;
    int isValidSink = 0;

    for (auto &i : file_name_hdl) {
        if (source_sink.first.cacheName == i.first) {
            source_sink.first.hdl = i.second;
        }
        if (source_sink.second.cacheName == i.first) {
            source_sink.second.hdl = i.second;
        }
    }

    const auto& mg = vm.methods();

    jitana::method_vertex_descriptor s_v = 0;
    jitana::method_vertex_descriptor t_v = 0;
    for (const auto& mv : boost::make_iterator_range(vertices(mg))) {
        const auto& cv = vm.find_class(mg[mv].class_hdl, false);
        if (!cv) {
            continue;
        }

        if ((mg[mv].hdl.idx == source_sink.first.methodIndex)
            && (mg[mv].hdl.file_hdl.idx == source_sink.first.hdl.idx)) {
            source_sink.first.methodName = mg[mv].jvm_hdl.unique_name;
            isValidSource = isValidSource + 1;
            s_v = mv;
            //std::cout << "s_mh= "<< mg[mv].hdl <<"\n";
        }

        if ((mg[mv].hdl.idx == source_sink.second.methodIndex)
            && (mg[mv].hdl.file_hdl.idx == source_sink.second.hdl.idx)) {
            source_sink.second.methodName = mg[mv].jvm_hdl.unique_name;
            isValidSink = isValidSink + 1;
            t_v = mv;
            //std::cout << "t_mh= "<< mg[mv].hdl <<"\n";
        }
    }

    if (isValidSink == 1 && isValidSource == 1) {
        jitana::method_reflection_edge_property eprop;
        boost::add_edge(s_v, t_v, eprop, vm.methods());

        ofs.open("output/output-reana/ref_methods_pair.csv",
                 std::ofstream::out | std::ofstream::app);
        if (!ofs_check.good()) {
            ofs << "Package_Name,S_MH,T_MH\n";
        }
        std::ifstream pkg("output/pkgName.txt");
        std::string pkgName,line;
        while (std::getline(pkg,line))
            pkgName = line;

        ofs << pkgName << ",";
        ofs << vm.methods()[s_v].hdl <<",";
        ofs << vm.methods()[t_v].hdl <<"\n";
    }
    if (isValidSink == 1 && isValidSource == 1) {
        /*DINA*/
        ref_flag = 1;
        /*DINA*/
        return 2;
    } else {
        return 1;
    }
}

void update_ref_vm() {
    std::ofstream ofs2;
    std::ifstream ofs_check2("output/output-reana/All_refs.csv");
    ofs2.open("output/output-reana/All_refs.csv",
              std::ofstream::out | std::ofstream::app);
    if (!ofs_check2.good()) {
        ofs2 << "App,S_MN,S_CN,T_MN,T_CN\n";
    }

    try {
        static std::vector<std::pair<ref_method, ref_method> >::iterator iterator_already_written_ref;

        for (auto &i : vRef) {
            if ((i.first.dexName.find("Jitana_Source_DN_NULL")
                 == std::string::npos)
                && (i.second.dexName.find("Jitana_Target_DN_NULL")
                    == std::string::npos)
                && (i.first.methodName.find("Jitana_Source_MN_NULL")
                    == std::string::npos)
                && (i.second.methodName.find("Jitana_Target_MN_NULL")
                    == std::string::npos)) {
                    iterator_already_written_ref =
                    find_if(already_written_ref.begin(),
                            already_written_ref.end(),
                            [&] (std::pair<ref_method, ref_method > &s)
                            {
                                /*DINA*/
                                ref_class_name = i.second.className;
                                //appPkgName = i.first.className;
                                //std::string refClassName = i.first.className;
                                //std::string refMethodsName = i.first.methodName;

                                /*DINA*/
                                return (
                                        (s.first.methodIndex == i.first.methodIndex)
                                        && (s.first.className == i.first.className)
                                        && (s.first.methodName == i.first.methodName)
                                        && (s.first.dexName == i.first.dexName)
                                        && (s.first.cacheName == i.first.cacheName)
                                        && (s.first.insn_offset == i.first.insn_offset)
                                        && (s.second.methodIndex == i.second.methodIndex)
                                        && (s.second.className == i.second.className)
                                        && (s.second.methodName == i.second.methodName)
                                        && (s.second.dexName == i.second.dexName)
                                        && (s.second.cacheName == i.second.cacheName)
                                        && (s.second.insn_offset == i.second.insn_offset)
                                        );
                            });
                }

            if (iterator_already_written_ref == already_written_ref.end()) {
                printed_ref.push_back(i);
                already_written_ref.push_back(i);
            }
        }

        std::ifstream pkg("output/pkgName.txt");
        std::string pkgName,line;
        while (std::getline(pkg,line))
            pkgName = line;

        //std::ofstream ofs1("output/output-reana/"+counter+"_"+pkgName+"_refs.csv");
        std::ofstream ofs1("output/output-reana/"+pkgName+"_refs.csv");

        for (auto &i : printed_ref) {

            int isValid = add_reflection_edge(i);
            if (isValid == 2) {
                ofs1 << "S_MI: " << i.first.methodIndex << " ; ";
                ofs1 << "S_MN: " << i.first.methodName << " ; ";
                ofs1 << "S_CN: " << i.first.className << " ; ";
                ofs1 << "S_DN: " << i.first.dexName << " ; ";
                ofs1 << "S_CaN: " << i.first.cacheName << " ; ";
                ofs1 << "S_IO: " << i.first.insn_offset << "; ";
                ofs1 << "T_MI: " << i.second.methodIndex << " ; ";
                ofs1 << "T_MN: " << i.second.methodName << " ; ";
                ofs1 << "T_CN: " << i.second.className << " ; ";
                ofs1 << "T_DN: " << i.second.dexName << " ; ";
                ofs1 << "T_CaN: " << i.second.cacheName << " ; ";
                ofs1 << "T_IO: " << i.second.insn_offset << std::endl;
                std::cout << "In side Valid == 1 : S_MI: " << i.first.methodName
                << "T_MI: " << i.second.methodName << std::endl;

                //check method graph, then find instruction graph
                /*DINA*/
                ofs2 << pkgName << ",";
                ofs2 << i.first.methodIndex << ",";
                ofs2 << i.first.methodName << ",";
                ofs2 << i.first.className << ",";
                ofs2 << i.first.dexName << ",";
                ofs2 << i.first.cacheName << ",";
                ofs2 << i.first.insn_offset << ",";
                ofs2 << i.second.methodIndex << ",";
                ofs2 << i.second.methodName << ",";
                ofs2 << i.second.className << "\n";
                ofs2 << i.second.dexName << ",";
                ofs2 << i.second.cacheName << ",";
                ofs2 << i.second.insn_offset << std::endl;
                /*DINA*/
            }
        }
    } catch (std::runtime_error e) {
        std::cerr << "error_update_ref_vm: " << e.what() << "\n";
    }
}

void update_ref() {
    jitana::jdwp_connection conn;
    try {
        conn.connect("localhost", "6100");
        auto id = conn.send_command(226, 1);
        jitana::jdwp_reply_header reply_header;
        conn.receive_reply_header(reply_header, id);

        auto count = conn.read_uint16();
        for (int i = 0; i < count; i++) {
            std::pair<ref_method, ref_method> refm;

            refm.first.methodIndex = conn.read_uint32();
            uint32_t s_mn_sz = conn.read_uint32();
            refm.first.methodName = conn.read_string(s_mn_sz);
            uint32_t s_cn_sz = conn.read_uint32();
            refm.first.className = conn.read_string(s_cn_sz);

            uint32_t s_dn_sz = conn.read_uint32();
            refm.first.dexName = conn.read_string(s_dn_sz);
            uint32_t s_cache_n_sz = conn.read_uint32();
            refm.first.cacheName = conn.read_string(s_cache_n_sz);

            refm.first.insn_offset = conn.read_uint16();

            refm.second.methodIndex = conn.read_uint32();
            uint32_t t_mn_sz = conn.read_uint32();
            refm.second.methodName = conn.read_string(t_mn_sz);
            uint32_t t_cn_sz = conn.read_uint32();
            refm.second.className = conn.read_string(t_cn_sz);

            uint32_t t_dn_sz = conn.read_uint32();
            refm.second.dexName = conn.read_string(t_dn_sz);
            uint32_t t_cache_n_sz = conn.read_uint32();
            refm.second.cacheName = conn.read_string(t_cache_n_sz);

            refm.second.insn_offset = conn.read_uint16();

            vRef.push_back(refm);
        }
        conn.close();
        update_ref_vm();
    } catch (std::runtime_error e) {
        std::cerr << "error_update_ref: " << e.what() << "\n";
        //signal(SIGINT, on_sigint);
    }
}
/* End ReAna */

void update(int /*value*/) {
    try {
        update_insn_counters();
    } catch (std::runtime_error e) {
        std::cerr << "error_update: " << e.what() << "\n";
    }

    /* Start ReAna */
    update_ref();
    /* End ReAna */

    update_graphs();
    if (periodic_output) {
        static int output_cnt = 0;
        if (output_cnt-- == 0) {
            output_cnt = 20;
        }
    }

    if (should_terminate) {
        std::cout << std::endl;
        exit(0);
    }

    glutPostRedisplay();
    glutTimerFunc(50, update, 0);
}

void run_reana(int argc, char** argv) {
    // Create a GLUT window.
    glutInit(&argc, argv);
    glutInitWindowPosition(window_x, window_y);
    glutInitWindowSize(window_width, window_height);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);
    window = glutCreateWindow(
                              title.empty() ? "Trace Visualizer" : title.c_str());
    glutMouseFunc(handle_mouse_event);
    glutMotionFunc(handle_motion_event);
    glutKeyboardFunc(handle_keyboard_event);
    glutReshapeFunc(reshape);
    glutDisplayFunc(display);

    // Initialize OpenGL.
    init_opengl();

    try {
        {
            std::vector<std::string> filenames = {
                "../../../dex/framework/core.dex",
                "../../../dex/framework/framework.dex",
                "../../../dex/framework/framework2.dex",
                "../../../dex/framework/ext.dex",
                "../../../dex/framework/conscrypt.dex",
                "../../../dex/framework/okhttp.dex",
                "../../../dex/framework/core-junit.dex",
                "../../../dex/framework/android.test.runner.dex",
                "../../../dex/framework/android.policy.dex" };
            jitana::class_loader loader(system_loader_hdl, "SystemLoader",
                                        begin(filenames), end(filenames));
            vm.add_loader(loader);
        }

        {
            std::vector<std::string> filenames;
            jitana::class_loader loader(app_loader_hdl, "AppLoader",
                                        begin(filenames), end(filenames));
            vm.add_loader(loader, system_loader_hdl);
        }

        update(0);

        signal(SIGINT, on_sigint);

        // Execute the main loop.
        glutMainLoop();

    } catch (const std::exception& e) {
        std::cerr << "Error: " << e.what() << "\n\n";
        std::cerr << "Please make sure that ";
        std::cerr << "all dependencies are installed correctly, and ";
        std::cerr << "the DEX files exist.\n";
    }
}

void dina_dynamic(int argc, char** argv)
{
    run_reana(argc, argv);
}

int main(int argc, char** argv) {
    std::ifstream pkg("output/pkgName.txt");
    std::string pkgName,line;
    while (std::getline(pkg,line))
        pkgName = line;

    appPkgName= line;

    dina_dynamic(argc, argv);

    return 1;
}

ext: cpp

max_stars_repo_name: Mohannadcse/DINA

max_issues_repo_name: Mohannadcse/DINA

max_forks_repo_name: Mohannadcse/DINA


text:
#include <boost/assert.hpp>
#include <cmath>
#include <limits>
#include <utility>

#include "mh_moves/mh_moves.hpp"
#include "sampling/simple.hpp"
#include "mh_moves/utility.hpp"
#include "detail/flip_possibility.hpp"

namespace biggles { namespace mh_moves {

shared_const_track_ptr_pair cross_over_at(shared_const_track_ptr_pair& tracks_to_cross, time_stamp time) {
    const track& bro(*(tracks_to_cross.first));
    const track& sis(*(tracks_to_cross.second));

    time_stamp bro_first = bro.first_time_stamp();
    time_stamp bro_last = bro.last_time_stamp();
    time_stamp sis_first = sis.first_time_stamp();
    time_stamp sis_last = sis.last_time_stamp();

    observation_collection::const_iterator bro_front_first = bro.observations().begin();
    observation_collection::const_iterator bro_front_last = bro.observations().lower_bound_for_time_stamp(time);
    observation_collection::const_iterator bro_back_first = bro_front_last;
    observation_collection::const_iterator bro_back_last = bro.observations().end();

    observation_collection::const_iterator sis_front_first = sis.observations().begin();
    observation_collection::const_iterator sis_front_last = sis.observations().lower_bound_for_time_stamp(time);
    observation_collection::const_iterator sis_back_first = sis_front_last;
    observation_collection::const_iterator sis_back_last = sis.observations().end();

    shared_track_ptr brosis(new track(bro_first, sis_last, bro_front_first, bro_front_last));
    for ( ; sis_back_first != sis_back_last; sis_back_first++)
        brosis->insert(*sis_back_first);
    shared_track_ptr sisbro(new track(sis_first, bro_last, sis_front_first, sis_front_last));
    for ( ; bro_back_first != bro_back_last; bro_back_first++)
        sisbro->insert(*bro_back_first);
    return shared_const_track_ptr_pair(brosis, sisbro);
}

bool cross_over(const partition_ptr_t& start_partition_ptr, partition_ptr_t& end_partition_ptr,
    float& proposal_density_ratio)
{
    const track_collection& tracks(start_partition_ptr->tracks());

    proposal_density_ratio = 0.f; // hmm ... this needs to be reconsidered; does a cross-over create/remove cross-over options?

    capability_recorder_ptr cap_rec_ptr = start_partition_ptr->get_capability_recorder();
    BOOST_ASSERT(cap_rec_ptr.get() not_eq 0); // there actually is something assigned

    const crossables_t& crossables = cap_rec_ptr->cross_over_pairs();
    if (crossables.empty())
        return 0;

    int num_crossables_before = crossables.size();

    const crossables_t::item_type& cross_over_item = *sampling::from_range(crossables.begin(), crossables.end());
    const crossables_t::value_type possibility_test_ptr(cross_over_item.value);
    if (not possibility_test_ptr->passed())
        return false;
    shared_const_track_ptr_pair tracks_to_cross(std::make_pair(cross_over_item.first, cross_over_item.second));
    time_stamp cross_over_time = possibility_test_ptr->sample_cross_over_time();

    if (not tracks.contains(tracks_to_cross.first)) { throw std::runtime_error("first track not found"); }
    if (not tracks.contains(tracks_to_cross.second)) { throw std::runtime_error("second track not found"); }
    if (tracks_to_cross.first == tracks_to_cross.second) { throw std::runtime_error("tracks identical"); }

    // cross over tracks
    shared_const_track_ptr_pair crossed_tracks = cross_over_at(tracks_to_cross, cross_over_time);

    BOOST_ASSERT(crossed_tracks.first->size()>1);
    BOOST_ASSERT(crossed_tracks.second->size()>1);

    cap_rec_ptr->add_erase_track(tracks_to_cross.first);
    cap_rec_ptr->add_erase_track(tracks_to_cross.second);
    cap_rec_ptr->add_insert_track(crossed_tracks.first);
    cap_rec_ptr->add_insert_track(crossed_tracks.second);
    cap_rec_ptr->set_editing_finished();

    // create new track partition
    shared_track_collection_ptr new_tracks(new track_collection(tracks));

    if (not new_tracks->contains(tracks_to_cross.first)) { throw std::runtime_error("NEW first track not found"); }
    if (not new_tracks->contains(tracks_to_cross.second)) { throw std::runtime_error("NEW second track not found"); }

    new_tracks->remove(tracks_to_cross.first);
    new_tracks->remove(tracks_to_cross.second);
    new_tracks->insert(crossed_tracks.first);
    new_tracks->insert(crossed_tracks.second);

    int num_crossables_after = cap_rec_ptr->num_crossables_if_commited(*new_tracks);
    proposal_density_ratio = -log(num_crossables_after) + log(num_crossables_before);

    const_clutter_ptr new_clutter(new clutter_t(start_partition_ptr->clutter()));
    end_partition_ptr = partition_ptr_t(
        new partition(start_partition_ptr->pool(), new_tracks, new_clutter, start_partition_ptr->expansion()));
    return true;
}

}

}

max_stars_repo_name: fbi-octopus/biggles

max_issues_repo_name: fbi-octopus/biggles

max_forks_repo_name: fbi-octopus/biggles