<commit_before>// This example demonstrates how classes can be extended / modified using
// mixins and templates
// Contruction problem is solved using variadic templates and perfect forwarding

#include <array>
#include <iostream>
#include <string>
#include <typeinfo>
#include <utility>
#include <vector>
#include <stdexcept>

#include "cpp_magic.h"
#include "timing.h"

using std::ostream;

/// default data member selector which does not remove any data members
template <typename Type, typename EnclosingClass, int id>
struct SelectAllMembers {
  typedef Type type;
};

/// Type for removed data members - which can be optimized out by the compiler
struct Nulltype {
  int empty[0] = {};
  Nulltype() {}
  template <typename T>
  Nulltype(T&& d) {}  // NOLINT(runtime/explicit)
  template <typename T>
  Nulltype& operator=(const T& other) {
    return *this;
  }

  template <typename T>
  Nulltype(std::initializer_list<T>) {}

  friend ostream& operator<<(ostream& out, const Nulltype& value) {
    return out;
  }
};

/// loops over variadic macro arguments and calls the specified operation
/// removes the first three parameters in each iteration, but adds the first one
/// again for the next call
/// e.g. LOOP(OP, a, b, c, d, e) will lead to:
/// OP(a, b, c)
/// OP(a, d, e)
/// For a more detailed explanation see `MAP` macro in `third_party/cpp_magic.h`
// clang-format off
#define LOOP(operation, first, second, third, ...)           \
  operation(first, second, third)                            \
  IF(HAS_ARGS(__VA_ARGS__))(                                 \
    DEFER2(_LOOP)()(operation, first, __VA_ARGS__))
#define _LOOP() LOOP
// clang-format on

/// adds the partial template specialization to select one clazz-member pair
/// only for internal usage - will be called inside LOOP
/// @param name:    selector name
/// @param clazz:   clazz of the data member
/// @param member:  data member name
#define INTERNAL_SELECT_MEMBER(name, clazz, member)             \
  template <typename Type>                                      \
  struct name<Type, clazz, clazz::getDataMemberUid##member()> { \
    typedef Type type;                                          \
  };

/// creates a new selector type
/// it only enables the specified data members if applied to a simulation object
/// others will be removed
#define NEW_MEMBER_SELECTOR(name, ...)                      \
  template <typename Type, typename EnclosingClass, int id> \
  struct name {                                             \
    typedef Nulltype type;                                  \
  };                                                        \
  EVAL(LOOP(INTERNAL_SELECT_MEMBER, name, __VA_ARGS__))

/// adds the partial template specialization to remove one clazz-member pair
/// only for internal usage - will be called inside LOOP
/// @param name:    selector name
/// @param clazz:   clazz of the data member
/// @param member:  data member name
#define INTERNAL_MEMBER_REMOVER(name, clazz, member)            \
  template <typename Type>                                      \
  struct name<Type, clazz, clazz::getDataMemberUid##member()> { \
    typedef Nulltype type;                                      \
  };

/// creates a new selector type
/// it removes the specified data members if applied to a simulation object
/// others will be kept -> inverse of NEW_MEMBER_SELECTOR
#define NEW_MEMBER_REMOVER(name, ...)                       \
  template <typename Type, typename EnclosingClass, int id> \
  struct name {                                             \
    typedef Type type;                                      \
  };                                                        \
  EVAL(LOOP(INTERNAL_MEMBER_REMOVER, name, __VA_ARGS__))

#define BDM_DEFAULT_TEMPLATE(template_param_name)                          \
  template <template <typename, typename, int> class template_param_name = \
                SelectAllMembers>

/// Macro to define data member for a simulation object
/// Hides complexity needed to conditionally remove the data member
#define BDM_DATA_MEMBER(access_modifier, type_name, var_name)               \
 public:                                                                    \
  static constexpr int getDataMemberUid##var_name() { return __COUNTER__; } \
  access_modifier:                                                          \
  typename TMemberSelector<type_name, self,                                 \
                           getDataMemberUid##var_name()>::type var_name

#define BDM_PUBLIC_MEMBER(type_name, var_name) \
  BDM_DATA_MEMBER(public, REMOVE_TRAILING_COMMAS(type_name), var_name)

#define BDM_PROTECTED_MEMBER(type_name, var_name) \
  BDM_DATA_MEMBER(protected, REMOVE_TRAILING_COMMAS(type_name), var_name)

#define BDM_PRIVATE_MEMBER(type_name, var_name) \
  BDM_DATA_MEMBER(private, REMOVE_TRAILING_COMMAS(type_name), var_name)

/// Macro to insert required boilerplate code into classes
/// @param: self_specifier: used to point to static members / functions of this
///         class - use PlaceholderType for template parameters without default
///         parameter - e.g.
///         `class A {};`
///           -> self_specifier: A
///         `template<typename T=DefaultValue> class B {};`
///           -> self_specifier: B<>
///         `template<typename T, typename U> class C {};`
///           -> self_specifier: C<PlaceholderType COMMA() PlaceholderType>
#define BDM_CLASS_HEADER(self_specifier)                                 \
 public:                                                                 \
  using self = self_specifier;                                           \
  template <typename Type, typename EnclosingClass, int id>              \
  using TMemberSelector =                                                \
      typename Base::template TMemberSelector<Type, EnclosingClass, id>; \
                                                                         \
 private:

// -----------------------------------------------------------------------------
// core library
BDM_DEFAULT_TEMPLATE(TTMemberSelector)
struct BdmSimObject {
  template <typename Type, typename EnclosingClass, int id>
  using TMemberSelector = TTMemberSelector<Type, EnclosingClass, id>;
};

/// This struct is used to access static functions / members of a class that
/// has template parameter(s) without a default value.
/// e.g.
/// ```
/// template <typename T> class Foo { static const int kBar = 3; };
/// Foo<PlaceholderType>::kBar
/// ```
/// The definition of the static function / member must be invariant of the
/// template parameter(s)
/// e.g. `Foo<PlaceholderType>::kBar == Foo<AnyOtherType>::kBar`
/// Usage solely to create a valid id for the scope operator. It is not allowed
/// to instantiate an object with template parameter PlaceholderType. The
/// following statement is invalid and will throw an exception at runtime:
/// `Foo<PlaceholderType> foo;`
struct PlaceholderType : public BdmSimObject<> {
  PlaceholderType() {
    throw std::logic_error(
        "Creating an instance of type PlaceholderType is not allowed. "
        "PlaceholderType should solely be used for creating a valid id "
        "for the scope operator");
  }
  template <class... A>
  PlaceholderType(const A&... a)
      : PlaceholderType() {}
};

template <typename Base = BdmSimObject<> >
class BaseCell : public Base {
  BDM_CLASS_HEADER(BaseCell<>);

 public:
  explicit BaseCell(const std::array<double, 3>& pos) : position_(pos) {}
  BaseCell() : position_{0, 0, 0} {}
  const std::array<double, 3>& GetPosition() const { return position_; }

 protected:
  BDM_PROTECTED_MEMBER(std::array<double COMMA() 3>, position_);
  BDM_PROTECTED_MEMBER(double, unused_) = 6.28;
};

template <typename Cell>
void CoreOp(Cell* cell) {
  std::cout << "[CoreOp] cell z-position: " << cell->GetPosition()[2]
            << std::endl;
}

// -----------------------------------------------------------------------------
// libraries for specific specialities add functionality - e.g. Neuroscience
class Neurite {};

// add Neurites to BaseCell
template <typename Base = BaseCell<> >
class Neuron : public Base {
  BDM_CLASS_HEADER(Neuron<>);

 public:
  template <class... A>
  explicit Neuron(const std::vector<Neurite>& neurites, const A&... a)
      : Base(a...), neurites_{neurites} {}
  Neuron() = default;
  const std::vector<Neurite>& GetNeurites() const { return neurites_; }

 private:
  BDM_PRIVATE_MEMBER(std::vector<Neurite>, neurites_);
};

// define easy to use templated type alias
BDM_DEFAULT_TEMPLATE(MemberSelector)
using BdmNeuron = Neuron<BaseCell<BdmSimObject<MemberSelector> > >;

// -----------------------------------------------------------------------------
// code written by life scientists using package core and Neuroscience extension
// extend Neuron definition provided by extension
template <typename Base>
class NeuronExtension : public Base {
  BDM_CLASS_HEADER(NeuronExtension<PlaceholderType>);

 public:
  template <class... A>
  explicit NeuronExtension(double foo, const A&... a)
      : Base(a...), foo_{foo} {}
  NeuronExtension() = default;
  double GetFoo() const {
    volatile auto& foo = Base::position_;
    return foo_;
  }

 private:
  BDM_PRIVATE_MEMBER(double, foo_) = 3.14;
};

// define easy to use templated type alias
BDM_DEFAULT_TEMPLATE(MemberSelector)
using MyExtendedNeuron =
    NeuronExtension<Neuron<BaseCell<BdmSimObject<MemberSelector> > > >;

// define some client code that processes extended neurons
template <typename Cell>
void CustomOp(const Cell& cell) {
  std::cout << "[CustomOp] cell #neurites " << cell->GetNeurites().size()
            << std::endl
            << "           cell.foo_      " << cell->GetFoo() << std::endl;
}

// define member selectors to remove data members that won't be used in the
// simulation
NEW_MEMBER_REMOVER(RemoveUnused, BaseCell<>, unused_);
NEW_MEMBER_SELECTOR(FooSelector, NeuronExtension<PlaceholderType>, foo_);

int main() {
  // --------------------------
  // use only classes from core
  BaseCell<> base;
  CoreOp(&base);

  // -------------------------------------
  // use class from neuroscience extension
  Neuron<> neuron;
  CoreOp(&neuron);

  BdmNeuron<> neuron1;
  // following statement is equivalent to:
  // Neuron<BaseCell<BdmSimObject<RemoveUnused> > >
  BdmNeuron<RemoveUnused> neuron_wo_unused;

  std::cout << "sizeof(neuron1)          " << sizeof(neuron1) << std::endl
            << "sizeof(neuron_wo_unused) " << sizeof(neuron_wo_unused)
            << std::endl;

  // ---------------------
  // use customized neuron
  NeuronExtension<Neuron<> > extended_neuron;
  CoreOp(&extended_neuron);
  CustomOp(&extended_neuron);

  // equivalent but with easier interface
  MyExtendedNeuron<> extended_neuron1(1.2, std::vector<Neurite>{Neurite()},
                                      std::array<double, 3>{1, 2, 3});
  CoreOp(&extended_neuron1);
  CustomOp(&extended_neuron1);

  // easier customizeble interface to
  MyExtendedNeuron<RemoveUnused> extended_neuron_wo_unused;
  MyExtendedNeuron<FooSelector> extended_neuron_only_foo;
  std::cout << "sizeof(extended_neuron1)          " << sizeof(extended_neuron1)
            << std::endl
            << "sizeof(extended_neuron_wo_unused) "
            << sizeof(extended_neuron_wo_unused) << std::endl
            << "sizeof(extended_neuron_only_foo)  "
            << sizeof(extended_neuron_only_foo) << std::endl;

  return 0;
}
<commit_msg>Fix compile error for non templated simulation objects<commit_after>// This example demonstrates how classes can be extended / modified using
// mixins and templates
// Contruction problem is solved using variadic templates and perfect forwarding

#include <array>
#include <iostream>
#include <string>
#include <typeinfo>
#include <utility>
#include <vector>
#include <stdexcept>

#include "cpp_magic.h"
#include "timing.h"

using std::ostream;

/// default data member selector which does not remove any data members
template <typename Type, typename EnclosingClass, int id>
struct SelectAllMembers {
  typedef Type type;
};

/// Type for removed data members - which can be optimized out by the compiler
struct Nulltype {
  int empty[0] = {};
  Nulltype() {}
  template <typename T>
  Nulltype(T&& d) {}  // NOLINT(runtime/explicit)
  template <typename T>
  Nulltype& operator=(const T& other) {
    return *this;
  }

  template <typename T>
  Nulltype(std::initializer_list<T>) {}

  friend ostream& operator<<(ostream& out, const Nulltype& value) {
    return out;
  }
};

/// loops over variadic macro arguments and calls the specified operation
/// removes the first three parameters in each iteration, but adds the first one
/// again for the next call
/// e.g. LOOP(OP, a, b, c, d, e) will lead to:
/// OP(a, b, c)
/// OP(a, d, e)
/// For a more detailed explanation see `MAP` macro in `third_party/cpp_magic.h`
// clang-format off
#define LOOP(operation, first, second, third, ...)           \
  operation(first, second, third)                            \
  IF(HAS_ARGS(__VA_ARGS__))(                                 \
    DEFER2(_LOOP)()(operation, first, __VA_ARGS__))
#define _LOOP() LOOP
// clang-format on

/// adds the partial template specialization to select one clazz-member pair
/// only for internal usage - will be called inside LOOP
/// @param name:    selector name
/// @param clazz:   clazz of the data member
/// @param member:  data member name
#define INTERNAL_SELECT_MEMBER(name, clazz, member)         \
  template <typename Type>                                  \
  struct name<Type, clazz, clazz::kDataMemberUid##member> { \
    typedef Type type;                                      \
  };

/// creates a new selector type
/// it only enables the specified data members if applied to a simulation object
/// others will be removed
#define NEW_MEMBER_SELECTOR(name, ...)                      \
  template <typename Type, typename EnclosingClass, int id> \
  struct name {                                             \
    typedef Nulltype type;                                  \
  };                                                        \
  EVAL(LOOP(INTERNAL_SELECT_MEMBER, name, __VA_ARGS__))

/// adds the partial template specialization to remove one clazz-member pair
/// only for internal usage - will be called inside LOOP
/// @param name:    selector name
/// @param clazz:   clazz of the data member
/// @param member:  data member name
#define INTERNAL_MEMBER_REMOVER(name, clazz, member)        \
  template <typename Type>                                  \
  struct name<Type, clazz, clazz::kDataMemberUid##member> { \
    typedef Nulltype type;                                  \
  };

/// creates a new selector type
/// it removes the specified data members if applied to a simulation object
/// others will be kept -> inverse of NEW_MEMBER_SELECTOR
#define NEW_MEMBER_REMOVER(name, ...)                       \
  template <typename Type, typename EnclosingClass, int id> \
  struct name {                                             \
    typedef Type type;                                      \
  };                                                        \
  EVAL(LOOP(INTERNAL_MEMBER_REMOVER, name, __VA_ARGS__))

#define BDM_DEFAULT_TEMPLATE(template_param_name)                          \
  template <template <typename, typename, int> class template_param_name = \
                SelectAllMembers>

/// Macro to define data member for a simulation object
/// Hides complexity needed to conditionally remove the data member
#define BDM_DATA_MEMBER(access_modifier, type_name, var_name)               \
 public:                                                                    \
  static const int kDataMemberUid##var_name = __COUNTER__;                  \
  access_modifier:                                                          \
  typename TMemberSelector<type_name, self, kDataMemberUid##var_name>::type \
      var_name

#define BDM_PUBLIC_MEMBER(type_name, var_name) \
  BDM_DATA_MEMBER(public, REMOVE_TRAILING_COMMAS(type_name), var_name)

#define BDM_PROTECTED_MEMBER(type_name, var_name) \
  BDM_DATA_MEMBER(protected, REMOVE_TRAILING_COMMAS(type_name), var_name)

#define BDM_PRIVATE_MEMBER(type_name, var_name) \
  BDM_DATA_MEMBER(private, REMOVE_TRAILING_COMMAS(type_name), var_name)

/// Macro to insert required boilerplate code into classes
/// @param: self_specifier: used to point to static members / functions of this
///         class - use PlaceholderType for template parameters without default
///         parameter - e.g.
///         `class A {};`
///           -> self_specifier: A
///         `template<typename T=DefaultValue> class B {};`
///           -> self_specifier: B<>
///         `template<typename T, typename U> class C {};`
///           -> self_specifier: C<PlaceholderType COMMA() PlaceholderType>
#define BDM_CLASS_HEADER(self_specifier)                                 \
 public:                                                                 \
  using self = self_specifier;                                           \
  template <typename Type, typename EnclosingClass, int id>              \
  using TMemberSelector =                                                \
      typename Base::template TMemberSelector<Type, EnclosingClass, id>; \
                                                                         \
 private:

// -----------------------------------------------------------------------------
// core library
BDM_DEFAULT_TEMPLATE(TTMemberSelector)
struct BdmSimObject {
  template <typename Type, typename EnclosingClass, int id>
  using TMemberSelector = TTMemberSelector<Type, EnclosingClass, id>;
};

/// This struct is used to access static functions / members of a class that
/// has template parameter(s) without a default value.
/// e.g.
/// ```
/// template <typename T> class Foo { static const int kBar = 3; };
/// Foo<PlaceholderType>::kBar
/// ```
/// The definition of the static function / member must be invariant of the
/// template parameter(s)
/// e.g. `Foo<PlaceholderType>::kBar == Foo<AnyOtherType>::kBar`
/// Usage solely to create a valid id for the scope operator. It is not allowed
/// to instantiate an object with template parameter PlaceholderType. The
/// following statement is invalid and will throw an exception at runtime:
/// `Foo<PlaceholderType> foo;`
struct PlaceholderType : public BdmSimObject<> {
  PlaceholderType() {
    throw std::logic_error(
        "Creating an instance of type PlaceholderType is not allowed. "
        "PlaceholderType should solely be used for creating a valid id "
        "for the scope operator");
  }
  template <class... A>
  PlaceholderType(const A&... a)
      : PlaceholderType() {}
};

template <typename Base = BdmSimObject<> >
class BaseCell : public Base {
  BDM_CLASS_HEADER(BaseCell<>);

 public:
  explicit BaseCell(const std::array<double, 3>& pos) : position_(pos) {}
  BaseCell() : position_{0, 0, 0} {}
  const std::array<double, 3>& GetPosition() const { return position_; }

 protected:
  BDM_PROTECTED_MEMBER(std::array<double COMMA() 3>, position_);
  BDM_PROTECTED_MEMBER(double, unused_) = 6.28;
};

template <typename Cell>
void CoreOp(Cell* cell) {
  std::cout << "[CoreOp] cell z-position: " << cell->GetPosition()[2]
            << std::endl;
}

// -----------------------------------------------------------------------------
// libraries for specific specialities add functionality - e.g. Neuroscience
class Neurite {};

// add Neurites to BaseCell
template <typename Base = BaseCell<> >
class Neuron : public Base {
  BDM_CLASS_HEADER(Neuron<>);

 public:
  template <class... A>
  explicit Neuron(const std::vector<Neurite>& neurites, const A&... a)
      : Base(a...), neurites_{neurites} {}
  Neuron() = default;
  const std::vector<Neurite>& GetNeurites() const { return neurites_; }

 private:
  BDM_PRIVATE_MEMBER(std::vector<Neurite>, neurites_);
};

// define easy to use templated type alias
BDM_DEFAULT_TEMPLATE(MemberSelector)
using BdmNeuron = Neuron<BaseCell<BdmSimObject<MemberSelector> > >;

// -----------------------------------------------------------------------------
// code written by life scientists using package core and Neuroscience extension
// extend Neuron definition provided by extension
template <typename Base>
class NeuronExtension : public Base {
  BDM_CLASS_HEADER(NeuronExtension<PlaceholderType>);

 public:
  template <class... A>
  explicit NeuronExtension(double foo, const A&... a)
      : Base(a...), foo_{foo} {}
  NeuronExtension() = default;
  double GetFoo() const {
    volatile auto& foo = Base::position_;
    return foo_;
  }

 private:
  BDM_PRIVATE_MEMBER(double, foo_) = 3.14;
};

// define easy to use templated type alias
BDM_DEFAULT_TEMPLATE(MemberSelector)
using MyExtendedNeuron =
    NeuronExtension<Neuron<BaseCell<BdmSimObject<MemberSelector> > > >;

// define some client code that processes extended neurons
template <typename Cell>
void CustomOp(const Cell& cell) {
  std::cout << "[CustomOp] cell #neurites " << cell->GetNeurites().size()
            << std::endl
            << "           cell.foo_      " << cell->GetFoo() << std::endl;
}

// define member selectors to remove data members that won't be used in the
// simulation
NEW_MEMBER_REMOVER(RemoveUnused, BaseCell<>, unused_);
NEW_MEMBER_SELECTOR(FooSelector, NeuronExtension<PlaceholderType>, foo_);

int main() {
  // --------------------------
  // use only classes from core
  BaseCell<> base;
  CoreOp(&base);

  // -------------------------------------
  // use class from neuroscience extension
  Neuron<> neuron;
  CoreOp(&neuron);

  BdmNeuron<> neuron1;
  // following statement is equivalent to:
  // Neuron<BaseCell<BdmSimObject<RemoveUnused> > >
  BdmNeuron<RemoveUnused> neuron_wo_unused;

  std::cout << "sizeof(neuron1)          " << sizeof(neuron1) << std::endl
            << "sizeof(neuron_wo_unused) " << sizeof(neuron_wo_unused)
            << std::endl;

  // ---------------------
  // use customized neuron
  NeuronExtension<Neuron<> > extended_neuron;
  CoreOp(&extended_neuron);
  CustomOp(&extended_neuron);

  // equivalent but with easier interface
  MyExtendedNeuron<> extended_neuron1(1.2, std::vector<Neurite>{Neurite()},
                                      std::array<double, 3>{1, 2, 3});
  CoreOp(&extended_neuron1);
  CustomOp(&extended_neuron1);

  // easier customizeble interface to
  MyExtendedNeuron<RemoveUnused> extended_neuron_wo_unused;
  MyExtendedNeuron<FooSelector> extended_neuron_only_foo;
  std::cout << "sizeof(extended_neuron1)          " << sizeof(extended_neuron1)
            << std::endl
            << "sizeof(extended_neuron_wo_unused) "
            << sizeof(extended_neuron_wo_unused) << std::endl
            << "sizeof(extended_neuron_only_foo)  "
            << sizeof(extended_neuron_only_foo) << std::endl;

  return 0;
}
<|endoftext|>


<commit_before>#include <stdio.h>
#include <iostream>     // std::cout
#include <fstream>      // std::ifstream
#include <cstdlib>
#include <cstring>
#include <string>
#include <sstream>
#include <vector>
#include <sys/types.h>
#include <dirent.h>
#include <cstdarg>
#include "omp.h"

using namespace std;

int const NUM_ROWS = 6;
int const NUM_COLS = 16;

inline std::string format(const char* fmt, ...){
    int size = 512;
    char* buffer = 0;
    buffer = new char[size];
    va_list vl;
    va_start(vl, fmt);
    int nsize = vsnprintf(buffer, size, fmt, vl);
    if(size<=nsize){ //fail delete buffer and try again
        delete[] buffer;
        buffer = 0;
        buffer = new char[nsize+1]; //+1 for /0
        nsize = vsnprintf(buffer, size, fmt, vl);
    }
    std::string ret(buffer);
    va_end(vl);
    delete[] buffer;
    return ret;
}

void printLines(int *arr){
	// OPTIONAL: print out the results
	// #pragma parallel for
	for (int j = 0; j < NUM_ROWS; j++) {
		for (int k = 0; k < NUM_COLS; k++){
			printf("%d ", arr[j * NUM_COLS + k] );
		}
		printf("\n");
	}
}

// windrose pseudocode

// Divide speed into 6 buckets
// Negative speeds are not allowed
int speedBucket(float data) {
	if (data < 0) return -1;

	// Stratified divide
	if (data < 1) {
		return 0;
	} else if (data < 3) {
		return 1;
	} else if (data < 5) {
		return 2;
	} else if (data < 7) {
		return 3;
	} else if (data < 9) {
		return 4;
	}else {
		return 5;
	}
}

// Divide 360 into 16 sectors
int directionBucket(float degrees) {
	int bucket = degrees / 22.5 ;
	return bucket;
}

// Main - load files and
int main(int argc, char *argv[]){

	int p[NUM_ROWS*NUM_COLS];

	// zero out array
	memset(p, 0, sizeof(p));
	// Scrub input
	std::string help ("-h");
	if (argc != 4 || help.compare(argv[1]) == 0 ) {
		printf("USAGE: ./windrose datafiledirectory stationId HH00\n");
		printf("Enter 0 for null values\n");
		return 0;
	}

	string station = argv[2];

	//load files in directory
	#pragma omp parallel for
	for (int i = 2; i<= 14; i++) {
		std::string filename  = format("./%smesonet-20%02d0621_%s.dat", argv[1], i, argv[3]);
		printf("%s\n", filename.c_str());

		// Cache line is 64 bytes - approx 2 lines

		ifstream datafile(filename.c_str(), ios::ate | ios::binary);
		long datasize = datafile.tellg();
		datafile.seekg(0);
		vector<unsigned char> bytes(datasize, 0);
		datafile.read((char*)&bytes[0], bytes.size());

		for (int j = 0; j < datasize; j+=(5+4*sizeof(int)))
		{
			int spd, dir, lat, lon;

			// 5 bytes station id
			// string stationid = string(1, bytes[j]);
			string stationid (reinterpret_cast<char const*>(&bytes[j]), 5);

			if (stationid == station) {
				// Intel CPU is little endian
				spd = (bytes[j+5]<<24)|(bytes[j+6]<<16)|(bytes[j+7]<<8)|(bytes[j+8]);
				dir = (bytes[j+9]<<24)|(bytes[j+10]<<16)|(bytes[j+11]<<8)|(bytes[j+12]);
				// printf("%s %d %d %d %d\n", stationid.c_str(), spd, dir, j+5, j+5+sizeof(int));

				int spdbckt = speedBucket(spd/100.);
				int dirbckt = directionBucket(dir/100.);

				#pragma omp critical
				{
					p[spdbckt* NUM_COLS + dirbckt]++;
				}
			}
		}
	}

	printLines(p);

  	return 0;

}

int dirNumFiles(char *directory)
{
	DIR *dp;
	int i;
 	struct dirent *ep;
  	dp = opendir ("./");

  	if (dp != NULL)
  	{
    	while (ep = readdir (dp))
      	i++;

    	(void) closedir (dp);
  	}
  	else
    	perror ("Couldn't open the directory");

  	printf("There's %d files in the current directory.\n", i);

  	return i;
}

<commit_msg>fix merge conflict<commit_after>#include <stdio.h>
#include <iostream>     // std::cout
#include <fstream>      // std::ifstream
#include <cstdlib>
#include <cstring>
#include <string>
#include <sstream>
#include <vector>
#include <sys/types.h>
#include <dirent.h>
#include <cstdarg>
#include "omp.h"

using namespace std;

int const NUM_ROWS = 6;
int const NUM_COLS = 16;
int p[NUM_ROWS*NUM_COLS];
string station;

inline std::string format(const char* fmt, ...){
    int size = 512;
    char* buffer = 0;
    buffer = new char[size];
    va_list vl;
    va_start(vl, fmt);
    int nsize = vsnprintf(buffer, size, fmt, vl);
    if(size<=nsize){ //fail delete buffer and try again
        delete[] buffer;
        buffer = 0;
        buffer = new char[nsize+1]; //+1 for /0
        nsize = vsnprintf(buffer, size, fmt, vl);
    }
    std::string ret(buffer);
    va_end(vl);
    delete[] buffer;
    return ret;
}

void printLines(int *arr){
	// OPTIONAL: print out the results
	// #pragma parallel for
	for (int j = 0; j < NUM_ROWS; j++) {
		for (int k = 0; k < NUM_COLS; k++){
			printf("%d ", arr[j * NUM_COLS + k] );
		}
		printf("\n");
	}
}

// windrose pseudocode

// Divide speed into 6 buckets
// Negative speeds are not allowed
int speedBucket(float data) {
	if (data < 0) return -1;

	// Stratified divide
	if (data < 1) {
		return 0;
	} else if (data < 3) {
		return 1;
	} else if (data < 5) {
		return 2;
	} else if (data < 7) {
		return 3;
	} else if (data < 9) {
		return 4;
	}else {
		return 5;
	}
}

// Divide 360 into 16 sectors
int directionBucket(float degrees) {
	int bucket = degrees / 22.5 ;
	return bucket;
}

void allocate(){
    memset(p, 0, sizeof(p));
}

void check(char *argv[],int argc){
    std::string help ("-h");
    if (argc != 4 || help.compare(argv[1]) == 0 ) {
        printf("USAGE: ./windrose datafiledirectory stationId HH00\n");
        printf("Enter 0 for null values\n");
        //return 0;
    }
    station = argv[2];
}

void calc(char *argv[],int argc){

    #pragma omp parallel for
    for (int i = 2; i<= 14; i++) {
        std::string filename  = format("./%smesonet-20%02d0621_%s.dat", argv[1], i, argv[3]);
        printf("%s\n", filename.c_str());

        // Cache line is 64 bytes - approx 2 lines

        ifstream datafile(filename.c_str(), ios::ate | ios::binary);
        long datasize = datafile.tellg();
        datafile.seekg(0);
        vector<unsigned char> bytes(datasize, 0);
        datafile.read((char*)&bytes[0], bytes.size());

        for (int j = 0; j < datasize; j+=(5+4*sizeof(int)))
        {
            int spd, dir, lat, lon;

            // 5 bytes station id
            // string stationid = string(1, bytes[j]);
            string stationid (reinterpret_cast<char const*>(&bytes[j]), 5);

            if (stationid == station) {
                // Intel CPU is little endian
                spd = (bytes[j+5]<<24)|(bytes[j+6]<<16)|(bytes[j+7]<<8)|(bytes[j+8]);
                dir = (bytes[j+9]<<24)|(bytes[j+10]<<16)|(bytes[j+11]<<8)|(bytes[j+12]);
                // printf("%s %d %d %d %d\n", stationid.c_str(), spd, dir, j+5, j+5+sizeof(int));

                int spdbckt = speedBucket(spd/100.);
                int dirbckt = directionBucket(dir/100.);

                #pragma omp critical
                {
                    p[spdbckt* NUM_COLS + dirbckt]++;
                }
            }
        }
    }
}

// Main - load files and
int main(int argc, char *argv[]){

    allocate();
	// Scrub input
    check(argv,argc);

    calc(argv,argc);

	printLines(p);
  	return 0;
}

int dirNumFiles(char *directory)
{
	DIR *dp;
	int i;
 	struct dirent *ep;
  	dp = opendir ("./");

  	if (dp != NULL)
  	{
    	while (ep = readdir (dp))
      	i++;

    	(void) closedir (dp);
  	}
  	else
    	perror ("Couldn't open the directory");

  	printf("There's %d files in the current directory.\n", i);
  	return i;
}<|endoftext|>


<commit_before>// ***************************************************************************
// HttpHeader_p.cpp (c) 2011 Derek Barnett
// Marth Lab, Department of Biology, Boston College
// ---------------------------------------------------------------------------
// Last modified: 13 January 2012 (DB)
// ---------------------------------------------------------------------------
// Provides a generic interface for parsing/generating HTTP headers, along
// with specialized request & response header types
// ***************************************************************************

#include "api/internal/io/HttpHeader_p.h"
using namespace BamTools;
using namespace BamTools::Internal;

#include <cstdlib>
#include <sstream>
#include <vector>
using namespace std;

namespace BamTools {

// -----------
// constants
// -----------

namespace Constants {

static const char CAR_RET_CHAR = '\r';
static const char COLON_CHAR   = ':';
static const char DOT_CHAR     = '.';
static const char NEWLINE_CHAR = '\n';
static const char SPACE_CHAR   = ' ';

static const string FIELD_NEWLINE   = "\r\n";
static const string FIELD_SEPARATOR = ": ";
static const string HTTP_STRING     = "HTTP/";

} // namespace Constants

// ------------------------
// static utility methods
// ------------------------

namespace Internal {

static inline
bool IsSpace(const char c) {
    const int n = static_cast<int>(c);
    return ( n== 0 || (n <= 13 && n >= 9) );
}

// split on hitting single char delim
static vector<string> Split(const string& source, const char delim) {
    stringstream ss(source);
    string field;
    vector<string> fields;
    while ( getline(ss, field, delim) )
        fields.push_back(field);
    return fields;
}

static string Trim(const string& source) {

    // skip if empty string
    if ( source.empty() )
        return source;

    // fetch string data
    const char*  s    = source.data(); // ignoring null-term on purpose
    const size_t size = source.size();
    size_t start = 0;
    size_t end   = size-1;

    // skip if no spaces at start or end
    if ( !IsSpace(s[start]) && !IsSpace( s[end] ) )
        return source;

    // remove leading whitespace
    while ( (start != end) && IsSpace(s[start]) )
        ++start;

    // remove trailing whitespace
    if ( start <= end ) {
        while ( end && IsSpace(s[end]) )
            --end;
    }

    // return result
    return string(s + start, (end-start) + 1);
}

} // namespace Internal
} // namespace BamTools

// ---------------------------
// HttpHeader implementation
// ---------------------------

HttpHeader::HttpHeader(void)
    : m_isValid(true)
    , m_majorVersion(1)
    , m_minorVersion(1)
{ }

HttpHeader::HttpHeader(const string& s)
    : m_isValid(true)
    , m_majorVersion(1)
    , m_minorVersion(1)
{
    Parse(s);
}

HttpHeader::~HttpHeader(void) { }

bool HttpHeader::ContainsKey(const string& key) const {
    return ( m_fields.find(key) != m_fields.end() );
}

int HttpHeader::GetMajorVersion(void) const {
    return m_majorVersion;
}

int HttpHeader::GetMinorVersion(void) const {
    return m_minorVersion;
}

string HttpHeader::GetValue(const string& key) {
    if ( ContainsKey(key) )
        return m_fields[key];
    else return string();
}

bool HttpHeader::IsValid(void) const {
    return m_isValid;
}

void HttpHeader::Parse(const string& s) {

    // trim whitespace from input string
    const string trimmed = Trim(s);

    // split into list of header lines
    vector<string> rawFields = Split(trimmed, Constants::NEWLINE_CHAR);

    // prep our 'cleaned' fields container
    vector<string> cleanFields;
    cleanFields.reserve(rawFields.size());

    // remove any empty fields and clean any trailing windows-style carriage returns ('\r')
    vector<string>::iterator rawFieldIter = rawFields.begin();
    vector<string>::iterator rawFieldEnd  = rawFields.end();
    for ( ; rawFieldIter != rawFieldEnd; ++rawFieldIter ) {
        string& field = (*rawFieldIter);

        // skip empty fields
        if ( field.empty() )
            continue;

        // remove carriage returns
        const size_t fieldSize = field.size();
        if ( field[fieldSize-1] == Constants::CAR_RET_CHAR )
            field.resize(fieldSize-1);

        // store cleaned field
        cleanFields.push_back(field);
    }

    // skip add'l processing if nothing here
    if ( cleanFields.empty() )
        return;

    // parse header lines
    int lineNumber = 0;
    vector<string>::const_iterator fieldIter = cleanFields.begin();
    vector<string>::const_iterator fieldEnd  = cleanFields.end();
    for ( ; fieldIter != fieldEnd; ++fieldIter, ++lineNumber ) {
        if ( !ParseLine( (*fieldIter), lineNumber ) ) {
            m_isValid = false;
            return;
        }
    }
}

bool HttpHeader::ParseLine(const string& line, int) {

    // find colon position, return failure if not found
    const size_t colonFound = line.find(Constants::COLON_CHAR);
    if ( colonFound == string::npos )
        return false;

    // store key/value (without leading/trailing whitespace) & return success
    const string key   = Trim(line.substr(0, colonFound));
    const string value = Trim(line.substr(colonFound+1));
    m_fields[key] = value;
    return true;
}

void HttpHeader::RemoveField(const string& key) {
    m_fields.erase(key);
}

void HttpHeader::SetField(const string& key, const string& value) {
    m_fields[key] = value;
}

void HttpHeader::SetValid(bool ok) {
    m_isValid = ok;
}

void HttpHeader::SetVersion(int major, int minor) {
    m_majorVersion = major;
    m_minorVersion = minor;
}

string HttpHeader::ToString(void) const {
    string result("");
    if ( m_isValid ) {
        map<string, string>::const_iterator fieldIter = m_fields.begin();
        map<string, string>::const_iterator fieldEnd  = m_fields.end();
        for ( ; fieldIter != fieldEnd; ++fieldIter ) {
            const string& key   = (*fieldIter).first;
            const string& value = (*fieldIter).second;
            const string& line  = key   + Constants::FIELD_SEPARATOR +
                                  value + Constants::FIELD_NEWLINE;
            result += line;
        }
    }
    return result;
}

// ----------------------------------
// HttpRequestHeader implementation
// ----------------------------------

HttpRequestHeader::HttpRequestHeader(const string& method,
                                     const string& resource,
                                     int majorVersion,
                                     int minorVersion)
    : HttpHeader()
    , m_method(method)
    , m_resource(resource)
{
    SetVersion(majorVersion, minorVersion);
}

HttpRequestHeader::~HttpRequestHeader(void) { }

string HttpRequestHeader::GetMethod(void) const {
    return m_method;
}

string HttpRequestHeader::GetResource(void) const {
    return m_resource;
}

bool HttpRequestHeader::ParseLine(const string& line, int lineNumber) {

    // if not 'request line', just let base class parse
    if ( lineNumber != 0 )
        return HttpHeader::ParseLine(line, lineNumber);

    // fail if empty line
    if ( line.empty() )
        return false;

    // walk through request line, storing positions
    //    GET /path/to/resource HTTP/1.1
    //    ^  ^^                ^^
    const size_t foundMethod = line.find_first_not_of(Constants::SPACE_CHAR); // skip any leading whitespace
    if ( foundMethod == string::npos ) return false;
    const size_t foundFirstSpace = line.find(Constants::SPACE_CHAR, foundMethod+1);
    if ( foundFirstSpace == string::npos ) return false;
    const size_t foundResource = line.find_first_not_of(Constants::SPACE_CHAR, foundFirstSpace+1);
    if ( foundResource == string::npos ) return false;
    const size_t foundSecondSpace = line.find(Constants::SPACE_CHAR, foundResource+1);
    if ( foundSecondSpace == string::npos ) return false;
    const size_t foundVersion= line.find_first_not_of(Constants::SPACE_CHAR, foundSecondSpace+1);
    if ( foundVersion == string::npos ) return false;

    // parse out method & resource
    m_method   = line.substr(foundMethod,   foundFirstSpace  - foundMethod);
    m_resource = line.substr(foundResource, foundSecondSpace - foundResource);

    // parse out version numbers
    const string temp = line.substr(foundVersion);
    if ( (temp.find(Constants::HTTP_STRING) != 0) || (temp.size() != 8) )
        return false;
    const int major = static_cast<int>(temp.at(5) - '0');
    const int minor = static_cast<int>(temp.at(7) - '0');
    SetVersion(major, minor);

    // if we get here, return success
    return true;
}

string HttpRequestHeader::ToString(void) const {
    stringstream request("");
    request << m_method   << Constants::SPACE_CHAR
            << m_resource << Constants::SPACE_CHAR
            << Constants::HTTP_STRING << GetMajorVersion() << Constants::DOT_CHAR << GetMinorVersion()
            << Constants::FIELD_NEWLINE
            << HttpHeader::ToString()
            << Constants::FIELD_NEWLINE;
    return request.str();
}

// -----------------------------------
// HttpResponseHeader implementation
// -----------------------------------

HttpResponseHeader::HttpResponseHeader(const int statusCode,
                                       const string& reason,
                                       int majorVersion,
                                       int minorVersion)

    : HttpHeader()
    , m_statusCode(statusCode)
    , m_reason(reason)
{
    SetVersion(majorVersion, minorVersion);
}

HttpResponseHeader::HttpResponseHeader(const string& s)
    : HttpHeader()
    , m_statusCode(0)
{
    Parse(s);
}

HttpResponseHeader::~HttpResponseHeader(void) { }

string HttpResponseHeader::GetReason(void) const  {
    return m_reason;
}

int HttpResponseHeader::GetStatusCode(void) const {
    return m_statusCode;
}

bool HttpResponseHeader::ParseLine(const string& line, int lineNumber) {

    // if not 'status line', just let base class
    if ( lineNumber != 0 )
        return HttpHeader::ParseLine(line, lineNumber);

    // fail if empty line
    if ( line.empty() )
        return false;

    // walk through status line, storing positions
    //    HTTP/1.1 200 OK
    //    ^       ^^  ^^

    const size_t foundVersion = line.find_first_not_of(Constants::SPACE_CHAR); // skip any leading whitespace
    if ( foundVersion == string::npos ) return false;
    const size_t foundFirstSpace = line.find(Constants::SPACE_CHAR, foundVersion+1);
    if ( foundFirstSpace == string::npos ) return false;
    const size_t foundStatusCode = line.find_first_not_of(Constants::SPACE_CHAR, foundFirstSpace+1);
    if ( foundStatusCode == string::npos ) return false;
    const size_t foundSecondSpace = line.find(Constants::SPACE_CHAR, foundStatusCode+1);
    if ( foundSecondSpace == string::npos ) return false;
    const size_t foundReason= line.find_first_not_of(Constants::SPACE_CHAR, foundSecondSpace+1);
    if ( foundReason == string::npos ) return false;

    // parse version numbers
    string temp = line.substr(foundVersion, foundFirstSpace - foundVersion);
    if ( (temp.find(Constants::HTTP_STRING) != 0) || (temp.size() != 8) )
        return false;
    const int major = static_cast<int>(temp.at(5) - '0');
    const int minor = static_cast<int>(temp.at(7) - '0');
    SetVersion(major, minor);

    // parse status code
    temp = line.substr(foundStatusCode, foundSecondSpace - foundStatusCode);
    if ( temp.size() != 3 ) return false;
    m_statusCode = atoi( temp.c_str() );

    // reason phrase should be everything else left
    m_reason = line.substr(foundReason);

    // if we get here, return success
    return true;
}

string HttpResponseHeader::ToString(void) const {
    stringstream response("");
    response << Constants::HTTP_STRING << GetMajorVersion() << Constants::DOT_CHAR << GetMinorVersion()
             << Constants::SPACE_CHAR  << m_statusCode
             << Constants::SPACE_CHAR  << m_reason
             << Constants::FIELD_NEWLINE
             << HttpHeader::ToString()
             << Constants::FIELD_NEWLINE;
    return response.str();
}
<commit_msg>one extra unicode string in the beginning of file<commit_after>// ***************************************************************************
// HttpHeader_p.cpp (c) 2011 Derek Barnett
// Marth Lab, Department of Biology, Boston College
// ---------------------------------------------------------------------------
// Last modified: 13 January 2012 (DB)
// ---------------------------------------------------------------------------
// Provides a generic interface for parsing/generating HTTP headers, along
// with specialized request & response header types
// ***************************************************************************

#include "api/internal/io/HttpHeader_p.h"
using namespace BamTools;
using namespace BamTools::Internal;

#include <cstdlib>
#include <sstream>
#include <vector>
using namespace std;

namespace BamTools {

// -----------
// constants
// -----------

namespace Constants {

static const char CAR_RET_CHAR = '\r';
static const char COLON_CHAR   = ':';
static const char DOT_CHAR     = '.';
static const char NEWLINE_CHAR = '\n';
static const char SPACE_CHAR   = ' ';

static const string FIELD_NEWLINE   = "\r\n";
static const string FIELD_SEPARATOR = ": ";
static const string HTTP_STRING     = "HTTP/";

} // namespace Constants

// ------------------------
// static utility methods
// ------------------------

namespace Internal {

static inline
bool IsSpace(const char c) {
    const int n = static_cast<int>(c);
    return ( n== 0 || (n <= 13 && n >= 9) );
}

// split on hitting single char delim
static vector<string> Split(const string& source, const char delim) {
    stringstream ss(source);
    string field;
    vector<string> fields;
    while ( getline(ss, field, delim) )
        fields.push_back(field);
    return fields;
}

static string Trim(const string& source) {

    // skip if empty string
    if ( source.empty() )
        return source;

    // fetch string data
    const char*  s    = source.data(); // ignoring null-term on purpose
    const size_t size = source.size();
    size_t start = 0;
    size_t end   = size-1;

    // skip if no spaces at start or end
    if ( !IsSpace(s[start]) && !IsSpace( s[end] ) )
        return source;

    // remove leading whitespace
    while ( (start != end) && IsSpace(s[start]) )
        ++start;

    // remove trailing whitespace
    if ( start <= end ) {
        while ( end && IsSpace(s[end]) )
            --end;
    }

    // return result
    return string(s + start, (end-start) + 1);
}

} // namespace Internal
} // namespace BamTools

// ---------------------------
// HttpHeader implementation
// ---------------------------

HttpHeader::HttpHeader(void)
    : m_isValid(true)
    , m_majorVersion(1)
    , m_minorVersion(1)
{ }

HttpHeader::HttpHeader(const string& s)
    : m_isValid(true)
    , m_majorVersion(1)
    , m_minorVersion(1)
{
    Parse(s);
}

HttpHeader::~HttpHeader(void) { }

bool HttpHeader::ContainsKey(const string& key) const {
    return ( m_fields.find(key) != m_fields.end() );
}

int HttpHeader::GetMajorVersion(void) const {
    return m_majorVersion;
}

int HttpHeader::GetMinorVersion(void) const {
    return m_minorVersion;
}

string HttpHeader::GetValue(const string& key) {
    if ( ContainsKey(key) )
        return m_fields[key];
    else return string();
}

bool HttpHeader::IsValid(void) const {
    return m_isValid;
}

void HttpHeader::Parse(const string& s) {

    // trim whitespace from input string
    const string trimmed = Trim(s);

    // split into list of header lines
    vector<string> rawFields = Split(trimmed, Constants::NEWLINE_CHAR);

    // prep our 'cleaned' fields container
    vector<string> cleanFields;
    cleanFields.reserve(rawFields.size());

    // remove any empty fields and clean any trailing windows-style carriage returns ('\r')
    vector<string>::iterator rawFieldIter = rawFields.begin();
    vector<string>::iterator rawFieldEnd  = rawFields.end();
    for ( ; rawFieldIter != rawFieldEnd; ++rawFieldIter ) {
        string& field = (*rawFieldIter);

        // skip empty fields
        if ( field.empty() )
            continue;

        // remove carriage returns
        const size_t fieldSize = field.size();
        if ( field[fieldSize-1] == Constants::CAR_RET_CHAR )
            field.resize(fieldSize-1);

        // store cleaned field
        cleanFields.push_back(field);
    }

    // skip add'l processing if nothing here
    if ( cleanFields.empty() )
        return;

    // parse header lines
    int lineNumber = 0;
    vector<string>::const_iterator fieldIter = cleanFields.begin();
    vector<string>::const_iterator fieldEnd  = cleanFields.end();
    for ( ; fieldIter != fieldEnd; ++fieldIter, ++lineNumber ) {
        if ( !ParseLine( (*fieldIter), lineNumber ) ) {
            m_isValid = false;
            return;
        }
    }
}

bool HttpHeader::ParseLine(const string& line, int) {

    // find colon position, return failure if not found
    const size_t colonFound = line.find(Constants::COLON_CHAR);
    if ( colonFound == string::npos )
        return false;

    // store key/value (without leading/trailing whitespace) & return success
    const string key   = Trim(line.substr(0, colonFound));
    const string value = Trim(line.substr(colonFound+1));
    m_fields[key] = value;
    return true;
}

void HttpHeader::RemoveField(const string& key) {
    m_fields.erase(key);
}

void HttpHeader::SetField(const string& key, const string& value) {
    m_fields[key] = value;
}

void HttpHeader::SetValid(bool ok) {
    m_isValid = ok;
}

void HttpHeader::SetVersion(int major, int minor) {
    m_majorVersion = major;
    m_minorVersion = minor;
}

string HttpHeader::ToString(void) const {
    string result("");
    if ( m_isValid ) {
        map<string, string>::const_iterator fieldIter = m_fields.begin();
        map<string, string>::const_iterator fieldEnd  = m_fields.end();
        for ( ; fieldIter != fieldEnd; ++fieldIter ) {
            const string& key   = (*fieldIter).first;
            const string& value = (*fieldIter).second;
            const string& line  = key   + Constants::FIELD_SEPARATOR +
                                  value + Constants::FIELD_NEWLINE;
            result += line;
        }
    }
    return result;
}

// ----------------------------------
// HttpRequestHeader implementation
// ----------------------------------

HttpRequestHeader::HttpRequestHeader(const string& method,
                                     const string& resource,
                                     int majorVersion,
                                     int minorVersion)
    : HttpHeader()
    , m_method(method)
    , m_resource(resource)
{
    SetVersion(majorVersion, minorVersion);
}

HttpRequestHeader::~HttpRequestHeader(void) { }

string HttpRequestHeader::GetMethod(void) const {
    return m_method;
}

string HttpRequestHeader::GetResource(void) const {
    return m_resource;
}

bool HttpRequestHeader::ParseLine(const string& line, int lineNumber) {

    // if not 'request line', just let base class parse
    if ( lineNumber != 0 )
        return HttpHeader::ParseLine(line, lineNumber);

    // fail if empty line
    if ( line.empty() )
        return false;

    // walk through request line, storing positions
    //    GET /path/to/resource HTTP/1.1
    //    ^  ^^                ^^
    const size_t foundMethod = line.find_first_not_of(Constants::SPACE_CHAR); // skip any leading whitespace
    if ( foundMethod == string::npos ) return false;
    const size_t foundFirstSpace = line.find(Constants::SPACE_CHAR, foundMethod+1);
    if ( foundFirstSpace == string::npos ) return false;
    const size_t foundResource = line.find_first_not_of(Constants::SPACE_CHAR, foundFirstSpace+1);
    if ( foundResource == string::npos ) return false;
    const size_t foundSecondSpace = line.find(Constants::SPACE_CHAR, foundResource+1);
    if ( foundSecondSpace == string::npos ) return false;
    const size_t foundVersion= line.find_first_not_of(Constants::SPACE_CHAR, foundSecondSpace+1);
    if ( foundVersion == string::npos ) return false;

    // parse out method & resource
    m_method   = line.substr(foundMethod,   foundFirstSpace  - foundMethod);
    m_resource = line.substr(foundResource, foundSecondSpace - foundResource);

    // parse out version numbers
    const string temp = line.substr(foundVersion);
    if ( (temp.find(Constants::HTTP_STRING) != 0) || (temp.size() != 8) )
        return false;
    const int major = static_cast<int>(temp.at(5) - '0');
    const int minor = static_cast<int>(temp.at(7) - '0');
    SetVersion(major, minor);

    // if we get here, return success
    return true;
}

string HttpRequestHeader::ToString(void) const {
    stringstream request("");
    request << m_method   << Constants::SPACE_CHAR
            << m_resource << Constants::SPACE_CHAR
            << Constants::HTTP_STRING << GetMajorVersion() << Constants::DOT_CHAR << GetMinorVersion()
            << Constants::FIELD_NEWLINE
            << HttpHeader::ToString()
            << Constants::FIELD_NEWLINE;
    return request.str();
}

// -----------------------------------
// HttpResponseHeader implementation
// -----------------------------------

HttpResponseHeader::HttpResponseHeader(const int statusCode,
                                       const string& reason,
                                       int majorVersion,
                                       int minorVersion)

    : HttpHeader()
    , m_statusCode(statusCode)
    , m_reason(reason)
{
    SetVersion(majorVersion, minorVersion);
}

HttpResponseHeader::HttpResponseHeader(const string& s)
    : HttpHeader()
    , m_statusCode(0)
{
    Parse(s);
}

HttpResponseHeader::~HttpResponseHeader(void) { }

string HttpResponseHeader::GetReason(void) const  {
    return m_reason;
}

int HttpResponseHeader::GetStatusCode(void) const {
    return m_statusCode;
}

bool HttpResponseHeader::ParseLine(const string& line, int lineNumber) {

    // if not 'status line', just let base class
    if ( lineNumber != 0 )
        return HttpHeader::ParseLine(line, lineNumber);

    // fail if empty line
    if ( line.empty() )
        return false;

    // walk through status line, storing positions
    //    HTTP/1.1 200 OK
    //    ^       ^^  ^^

    const size_t foundVersion = line.find_first_not_of(Constants::SPACE_CHAR); // skip any leading whitespace
    if ( foundVersion == string::npos ) return false;
    const size_t foundFirstSpace = line.find(Constants::SPACE_CHAR, foundVersion+1);
    if ( foundFirstSpace == string::npos ) return false;
    const size_t foundStatusCode = line.find_first_not_of(Constants::SPACE_CHAR, foundFirstSpace+1);
    if ( foundStatusCode == string::npos ) return false;
    const size_t foundSecondSpace = line.find(Constants::SPACE_CHAR, foundStatusCode+1);
    if ( foundSecondSpace == string::npos ) return false;
    const size_t foundReason= line.find_first_not_of(Constants::SPACE_CHAR, foundSecondSpace+1);
    if ( foundReason == string::npos ) return false;

    // parse version numbers
    string temp = line.substr(foundVersion, foundFirstSpace - foundVersion);
    if ( (temp.find(Constants::HTTP_STRING) != 0) || (temp.size() != 8) )
        return false;
    const int major = static_cast<int>(temp.at(5) - '0');
    const int minor = static_cast<int>(temp.at(7) - '0');
    SetVersion(major, minor);

    // parse status code
    temp = line.substr(foundStatusCode, foundSecondSpace - foundStatusCode);
    if ( temp.size() != 3 ) return false;
    m_statusCode = atoi( temp.c_str() );

    // reason phrase should be everything else left
    m_reason = line.substr(foundReason);

    // if we get here, return success
    return true;
}

string HttpResponseHeader::ToString(void) const {
    stringstream response("");
    response << Constants::HTTP_STRING << GetMajorVersion() << Constants::DOT_CHAR << GetMinorVersion()
             << Constants::SPACE_CHAR  << m_statusCode
             << Constants::SPACE_CHAR  << m_reason
             << Constants::FIELD_NEWLINE
             << HttpHeader::ToString()
             << Constants::FIELD_NEWLINE;
    return response.str();
}
<|endoftext|>


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

  Library: CTK

  Copyright (c) German Cancer Research Center,
    Division of Medical and Biological Informatics

  Licensed 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.

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

#include "ctkHostAppExampleWidget.h"
#include "ui_ctkHostAppExampleWidget.h"
#include "ctkExampleDicomHost.h"
#include "ctkDicomAppService.h"
#include <ctkDicomAppHostingTypesHelper.h>

#include <QDebug>
#include <QFileDialog>
#include <QProcess>

ctkHostAppExampleWidget::ctkHostAppExampleWidget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::ctkHostAppExampleWidget)
{
  qDebug() << "setup ui";
  ui->setupUi(this);
  ui->crashLabel->setVisible(false);
  ui->messageOutput->setVisible(false);
  this->host = new ctkExampleDicomHost(ui->placeholderFrame);

  connect(&this->host->getAppProcess(),SIGNAL(error(QProcess::ProcessError)),SLOT(appProcessError(QProcess::ProcessError)));
  connect(&this->host->getAppProcess(),SIGNAL(stateChanged(QProcess::ProcessState)),SLOT(appProcessStateChanged(QProcess::ProcessState)));
  connect(ui->placeholderFrame,SIGNAL(resized()),SLOT(placeholderResized()));
  connect(this->host,SIGNAL( stateChangeReceived(ctkDicomAppHosting::State)),SLOT(appStateChanged(ctkDicomAppHosting::State)));

}

ctkHostAppExampleWidget::~ctkHostAppExampleWidget()
{
  delete host;
  delete ui;
}

void ctkHostAppExampleWidget::startButtonClicked()
{
  qDebug() << "start button clicked";
  if (host)
  {
    host->StartApplication(appFileName);
  }
}

void ctkHostAppExampleWidget::runButtonClicked()
{
  qDebug() << "run button clicked";
  if (host)
  {
    bool reply = host->getDicomAppService()->setState(ctkDicomAppHosting::INPROGRESS);
    qDebug() << "  setState(INPROGRESS) returned: " << reply;
  }
}

void ctkHostAppExampleWidget::stopButtonClicked()
{
  qDebug() << "stop button clicked";
}

void ctkHostAppExampleWidget::loadButtonClicked()
{
  qDebug() << "load button clicked";
  this->setAppFileName(QFileDialog::getOpenFileName(this,"Choose hosted application",QApplication::applicationDirPath()));
}

void ctkHostAppExampleWidget::setAppFileName(QString name)
{
  this->appFileName = name;
  if (QFile(this->appFileName).permissions() & QFile::ExeUser )
  {
    this->ui->applicationPathLabel->setText(this->appFileName);
  }
  else
  {
    this->ui->applicationPathLabel->setText(QString("Not executable:").append(this->appFileName));
  }
}

void ctkHostAppExampleWidget::appProcessError(QProcess::ProcessError error)
{
  if (error == QProcess::Crashed)
  {
    qDebug() << "crash detected";
    ui->crashLabel->setVisible(true);
  }
}

void ctkHostAppExampleWidget::appProcessStateChanged(QProcess::ProcessState state)
{
  QString labelText;
  switch (state){
  case QProcess::Running:
    ui->processStateLabel->setText("Running");
    break;
  case QProcess::NotRunning:
    if (host->getAppProcess().exitStatus() == QProcess::CrashExit )
    {
      labelText = "crashed";
    }
    else
    {
      labelText = "Not Running, last exit code ";
      labelText.append(QString::number(host->getAppProcess().exitCode()));
    }
    ui->processStateLabel->setText(labelText);
    break;
  case QProcess::Starting:
    ui->processStateLabel->setText("Starting");
    break;
  default:
    ;
  }
}

void ctkHostAppExampleWidget::placeholderResized()
{
  qDebug() << "resized";
  //ui->placeholderFrame->printPosition();
}

void ctkHostAppExampleWidget::appStateChanged(ctkDicomAppHosting::State state)
{
  ui->statusLabel->setText(ctkDicomSoapState::toStringValue(state));
}
<commit_msg>Fixed type in signal name.<commit_after>/*=============================================================================

  Library: CTK

  Copyright (c) German Cancer Research Center,
    Division of Medical and Biological Informatics

  Licensed 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.

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

#include "ctkHostAppExampleWidget.h"
#include "ui_ctkHostAppExampleWidget.h"
#include "ctkExampleDicomHost.h"
#include "ctkDicomAppService.h"
#include <ctkDicomAppHostingTypesHelper.h>

#include <QDebug>
#include <QFileDialog>
#include <QProcess>

ctkHostAppExampleWidget::ctkHostAppExampleWidget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::ctkHostAppExampleWidget)
{
  qDebug() << "setup ui";
  ui->setupUi(this);
  ui->crashLabel->setVisible(false);
  ui->messageOutput->setVisible(false);
  this->host = new ctkExampleDicomHost(ui->placeholderFrame);

  connect(&this->host->getAppProcess(),SIGNAL(error(QProcess::ProcessError)),SLOT(appProcessError(QProcess::ProcessError)));
  connect(&this->host->getAppProcess(),SIGNAL(stateChanged(QProcess::ProcessState)),SLOT(appProcessStateChanged(QProcess::ProcessState)));
  connect(ui->placeholderFrame,SIGNAL(resized()),SLOT(placeholderResized()));
  connect(this->host,SIGNAL( stateChangedReceived(ctkDicomAppHosting::State)),SLOT(appStateChanged(ctkDicomAppHosting::State)));

}

ctkHostAppExampleWidget::~ctkHostAppExampleWidget()
{
  delete host;
  delete ui;
}

void ctkHostAppExampleWidget::startButtonClicked()
{
  qDebug() << "start button clicked";
  if (host)
  {
    host->StartApplication(appFileName);
  }
}

void ctkHostAppExampleWidget::runButtonClicked()
{
  qDebug() << "run button clicked";
  if (host)
  {
    bool reply = host->getDicomAppService()->setState(ctkDicomAppHosting::INPROGRESS);
    qDebug() << "  setState(INPROGRESS) returned: " << reply;
  }
}

void ctkHostAppExampleWidget::stopButtonClicked()
{
  qDebug() << "stop button clicked";
}

void ctkHostAppExampleWidget::loadButtonClicked()
{
  qDebug() << "load button clicked";
  this->setAppFileName(QFileDialog::getOpenFileName(this,"Choose hosted application",QApplication::applicationDirPath()));
}

void ctkHostAppExampleWidget::setAppFileName(QString name)
{
  this->appFileName = name;
  if (QFile(this->appFileName).permissions() & QFile::ExeUser )
  {
    this->ui->applicationPathLabel->setText(this->appFileName);
  }
  else
  {
    this->ui->applicationPathLabel->setText(QString("Not executable:").append(this->appFileName));
  }
}

void ctkHostAppExampleWidget::appProcessError(QProcess::ProcessError error)
{
  if (error == QProcess::Crashed)
  {
    qDebug() << "crash detected";
    ui->crashLabel->setVisible(true);
  }
}

void ctkHostAppExampleWidget::appProcessStateChanged(QProcess::ProcessState state)
{
  QString labelText;
  switch (state){
  case QProcess::Running:
    ui->processStateLabel->setText("Running");
    break;
  case QProcess::NotRunning:
    if (host->getAppProcess().exitStatus() == QProcess::CrashExit )
    {
      labelText = "crashed";
    }
    else
    {
      labelText = "Not Running, last exit code ";
      labelText.append(QString::number(host->getAppProcess().exitCode()));
    }
    ui->processStateLabel->setText(labelText);
    break;
  case QProcess::Starting:
    ui->processStateLabel->setText("Starting");
    break;
  default:
    ;
  }
}

void ctkHostAppExampleWidget::placeholderResized()
{
  qDebug() << "resized";
  //ui->placeholderFrame->printPosition();
}

void ctkHostAppExampleWidget::appStateChanged(ctkDicomAppHosting::State state)
{
  ui->statusLabel->setText(ctkDicomSoapState::toStringValue(state));
}
<|endoftext|>


<commit_before>#include "Settings.h"

#include <Shlwapi.h>
#include <algorithm>

#include "Error.h"
#include "HotkeyInfo.h"
#include "Logger.h"
#include "Monitor.h"
#include "Skin.h"
#include "StringUtils.h"

#define XML_AUDIODEV "audioDeviceID"
#define XML_HIDE_WHENFULL "hideFullscreen"
#define XML_HIDEANIM "hideAnimation"
#define XML_HIDETIME "hideDelay"
#define XML_HIDESPEED "hideSpeed"
#define XML_LANGUAGE "language"
#define XML_MONITOR "monitor"
#define XML_NOTIFYICON "notifyIcon"
#define XML_ONTOP "onTop"
#define XML_OSD_OFFSET "osdEdgeOffset"
#define XML_OSD_POS "osdPosition"
#define XML_OSD_X "osdX"
#define XML_OSD_Y "osdY"
#define XML_SKIN "skin"
#define XML_SOUNDS "soundEffects"

std::wstring Settings::_appDir(L"");
Settings *Settings::instance;

std::vector<std::wstring> Settings::OSDPosNames = {
    L"top",
    L"left",
    L"right",
    L"bottom",
    L"center",
    L"top-left",
    L"top-right",
    L"bottom-left",
    L"bottom-right",
    L"custom"
};

Settings *Settings::Instance() {
    if (instance == NULL) {
        instance = new Settings();
    }
    return instance;
}

void Settings::Load() {
    _file = AppDir() + L"\\Settings.xml";
    CLOG(L"Loading settings: %s", _file.c_str());

    std::string u8FileName = StringUtils::Narrow(_file);
    tinyxml2::XMLError result = _xml.LoadFile(u8FileName.c_str());
    if (result != tinyxml2::XMLError::XML_SUCCESS) {
        throw std::runtime_error("Failed to parse XML file");
    }

    _root = _xml.GetDocument()->FirstChildElement("settings");
    if (_root == NULL) {
        throw std::runtime_error("Could not find root XML element");
    }
}

int Settings::Save() {
    FILE *stream;
    errno_t err = _wfopen_s(&stream, _file.c_str(), L"w");
    if (err != 0 || stream == NULL) {
        CLOG(L"Could not open settings file for writing!");
        return 100 + err;
    }
    tinyxml2::XMLError result = _xml.SaveFile(stream);
    fclose(stream);
    return result;
}

std::wstring Settings::AppDir() {
    if (_appDir.empty()) {
        wchar_t path[MAX_PATH] = { 0 };
        GetModuleFileName(NULL, path, MAX_PATH);
        PathRemoveFileSpec(path);
        _appDir = std::wstring(path);
    }
    return _appDir;
}

std::wstring Settings::SkinDir() {
    return AppDir() + L"\\" + SKIN_DIR;
}

std::wstring Settings::SettingsApp() {
    return Settings::AppDir() + L"\\" + SETTINGS_APP;
}

std::wstring Settings::LanguagesDir() {
    return AppDir() + L"\\" + LANG_DIR;
}

void Settings::LaunchSettingsApp() {
    std::wstring app = SettingsApp();

    CLOG(L"Opening Settings App: %s", app.c_str());
    int exec = (int) ShellExecute(
        NULL, L"open", app.c_str(), NULL, NULL, SW_SHOWNORMAL);

    if (exec <= 32) {
        Error::ErrorMessage(GENERR_NOTFOUND, app);
    }
}

std::wstring Settings::AudioDeviceID() {
    return GetText(XML_AUDIODEV);
}

std::wstring Settings::LanguageName() {
    std::wstring lang = GetText(XML_LANGUAGE);

    if (lang == L"") {
        return DEFAULT_LANGUAGE;
    } else {
        return lang;
    }
}

bool Settings::AlwaysOnTop() {
    return GetEnabled(XML_ONTOP);
}

void Settings::AlwaysOnTop(bool enable) {
    SetEnabled(XML_ONTOP, enable);
}

bool Settings::HideFullscreen() {
    return GetEnabled(XML_HIDE_WHENFULL);
}

void Settings::HideFullscreen(bool enable) {
    SetEnabled(XML_HIDE_WHENFULL, enable);
}

std::wstring Settings::Monitor() {
    return GetText(XML_MONITOR);
}

void Settings::Monitor(std::wstring monitorName) {
    SetText(XML_MONITOR, StringUtils::Narrow(monitorName));
}

int Settings::OSDEdgeOffset() {
    if (HasSetting(XML_OSD_OFFSET)) {
        return GetInt(XML_OSD_OFFSET);
    } else {
        return DEFAULT_OSD_OFFSET;
    }
}

void Settings::OSDEdgeOffset(int offset) {
    SetInt(XML_OSD_OFFSET, offset);
}

Settings::OSDPos Settings::OSDPosition() {
    std::wstring pos = GetText(XML_OSD_POS);
    std::transform(pos.begin(), pos.end(), pos.begin(), ::tolower);

    for (unsigned int i = 0; i < OSDPosNames.size(); ++i) {
        if (pos == OSDPosNames[i]) {
            return (Settings::OSDPos) i;
        }
    }

    return DEFAULT_OSD_POS;
}

void Settings::OSDPosition(OSDPos pos) {
    std::wstring posStr = OSDPosNames[(int) pos];
    SetText(XML_OSD_POS, StringUtils::Narrow(posStr));
}

int Settings::OSDX() {
    return GetInt(XML_OSD_X);
}

void Settings::OSDX(int x) {
    SetInt(XML_OSD_X, x);
}

int Settings::OSDY() {
    return GetInt(XML_OSD_Y);
}

void Settings::OSDY(int y) {
    SetInt(XML_OSD_Y, y);
}

AnimationTypes::HideAnimation Settings::HideAnim() {
    std::wstring anim = GetText(XML_HIDEANIM);
    CLOG(L"looking for anim: %s", anim.c_str());
    std::transform(anim.begin(), anim.end(), anim.begin(), ::tolower);

    std::vector<std::wstring> *names = &AnimationTypes::HideAnimationNames;
    for (unsigned int i = 0; i < names->size(); ++i) {
        if (anim == (*names)[i]) {
            CLOG(L"found %d", i);
            return (AnimationTypes::HideAnimation) i;
        }
    }

    return DEFAULT_HIDE_ANIM;
}

void Settings::HideAnim(AnimationTypes::HideAnimation anim) {
    std::wstring hideStr = AnimationTypes::HideAnimationNames[(int) anim];
    SetText(XML_HIDEANIM, StringUtils::Narrow(hideStr));
}

int Settings::HideDelay() {
    return GetInt(XML_HIDETIME);
}

void Settings::HideDelay(int delay) {
    SetInt(XML_HIDETIME, delay);
}

int Settings::HideSpeed() {
    return GetInt(XML_HIDESPEED);
}

void Settings::HideSpeed(int speed) {
    SetInt(XML_HIDESPEED, speed);
}

bool Settings::CurrentSkin(std::wstring skinName) {
    std::string name = StringUtils::Narrow(skinName);
    std::wstring xml = SkinXML(skinName);
    if (PathFileExists(xml.c_str()) == FALSE) {
        return false;
    }

    SetText(XML_SKIN, name);
    return true;
}

std::wstring Settings::CurrentSkin() {
    std::wstring name = GetText("skin");

    if (name == L"") {
        return DEFAULT_SKIN;
    } else {
        return name;
    }
}

std::wstring Settings::SkinXML() {
    return SkinXML(CurrentSkin());
}

std::wstring Settings::SkinXML(std::wstring skinName) {
    std::wstring skinXML = Settings::AppDir() + L"\\" + SKINS_DIR L"\\"
        + skinName + L"\\" SKIN_XML;
    return skinXML;
}

std::unordered_map<int, HotkeyInfo> Settings::Hotkeys() {
    std::unordered_map<int, HotkeyInfo> keyMappings;

    tinyxml2::XMLElement *hotkeys = _root->FirstChildElement("hotkeys");
    if (hotkeys == NULL) {
        return keyMappings;
    }

    tinyxml2::XMLElement *hotkey = hotkeys->FirstChildElement("hotkey");
    for (; hotkey != NULL; hotkey = hotkey->NextSiblingElement()) {
        int action = -1;
        hotkey->QueryIntAttribute("action", &action);
        if (action == -1) {
            CLOG(L"No action provided for hotkey; skipping");
            continue;
        }

        int combination = -1;
        hotkey->QueryIntAttribute("combination", &combination);
        if (combination == -1) {
            CLOG(L"No key combination provided for hotkey; skipping");
            continue;
        }

        HotkeyInfo hki;
        hki.action = action;
        hki.keyCombination = combination;

        /* Does this hotkey action have any arguments? */
        tinyxml2::XMLElement *arg = hotkey->FirstChildElement("arg");
        for (; arg != NULL; arg = arg->NextSiblingElement()) {
            const char *argStr = arg->GetText();
            hki.args.push_back(StringUtils::Widen(argStr));
        }

        /* Whew, we made it! */
        CLOG(L"%s", hki.ToString().c_str());
        keyMappings[combination] = hki;
    }

    return keyMappings;
}

void Settings::Hotkeys(std::vector<HotkeyInfo> hotkeys) {
    tinyxml2::XMLElement *hkElem = GetOrCreateElement("hotkeys");
    hkElem->DeleteChildren();

    for (HotkeyInfo hotkey : hotkeys) {
        tinyxml2::XMLElement *hk = _xml.NewElement("hotkey");

        hk->SetAttribute("combination", hotkey.keyCombination);
        hk->SetAttribute("action", hotkey.action);

        if (hotkey.args.size() > 0) {
            for (std::wstring arg : hotkey.args) {
                tinyxml2::XMLElement *argElem = _xml.NewElement("arg");
                argElem->SetText(StringUtils::Narrow(arg).c_str());
                hk->InsertEndChild(argElem);
            }
        }

        hkElem->InsertEndChild(hk);
    }
}

bool Settings::NotifyIconEnabled() {
    return GetEnabled(XML_NOTIFYICON);
}

void Settings::NotifyIconEnabled(bool enable) {
    SetEnabled(XML_NOTIFYICON, enable);
}

bool Settings::SoundEffectsEnabled() {
    return GetEnabled(XML_SOUNDS);
}

void Settings::SoundEffectsEnabled(bool enable) {
    SetEnabled(XML_SOUNDS, enable);
}

bool Settings::HasSetting(std::string elementName) {
    tinyxml2::XMLElement *el = _root->FirstChildElement(elementName.c_str());
    return (el != NULL);
}

bool Settings::GetEnabled(std::string elementName) {
    tinyxml2::XMLElement *el = _root->FirstChildElement(elementName.c_str());
    if (el == NULL) {
        std::wstring elStr = StringUtils::Widen(elementName);
        CLOG(L"Warning: XML element '%s' not found", elStr.c_str());
        return false;
    } else {
        bool val = false;
        el->QueryBoolText(&val);
        return val;
    }
}

void Settings::SetEnabled(std::string elementName, bool enabled) {
    tinyxml2::XMLElement *el = GetOrCreateElement(elementName);
    el->SetText(enabled ? "true" : "false");
}

std::wstring Settings::GetText(std::string elementName) {
    tinyxml2::XMLElement *el = _root->FirstChildElement(elementName.c_str());
    if (el == NULL) {
        CLOG(L"Warning: XML element %s not found",
            StringUtils::Widen(elementName).c_str());
        return L"";
    }

    const char* str = el->GetText();
    if (str == NULL) {
        return L"";
    } else {
        return StringUtils::Widen(str);
    }
}

void Settings::SetText(std::string elementName, std::string text) {
    tinyxml2::XMLElement *el = GetOrCreateElement(elementName);
    el->SetText(text.c_str());
}

int Settings::GetInt(std::string elementName) {
    tinyxml2::XMLElement *el = _root->FirstChildElement(elementName.c_str());
    if (el == NULL) {
        std::wstring elStr = StringUtils::Widen(elementName);
        CLOG(L"Warning: XML element '%s' not found", elStr.c_str());
        return 0;
    }

    int val = 0;
    el->QueryIntText(&val);
    return val;
}

void Settings::SetInt(std::string elementName, int value) {
    tinyxml2::XMLElement *el = GetOrCreateElement(elementName);
    el->SetText(value);
}

tinyxml2::XMLElement *Settings::GetOrCreateElement(std::string elementName) {
    tinyxml2::XMLElement *el = _root->FirstChildElement(elementName.c_str());
    if (el == NULL) {
        el = _xml.NewElement(elementName.c_str());
        _root->InsertEndChild(el);
    }
    return el;
}<commit_msg>Remove debugging info<commit_after>#include "Settings.h"

#include <Shlwapi.h>
#include <algorithm>

#include "Error.h"
#include "HotkeyInfo.h"
#include "Logger.h"
#include "Monitor.h"
#include "Skin.h"
#include "StringUtils.h"

#define XML_AUDIODEV "audioDeviceID"
#define XML_HIDE_WHENFULL "hideFullscreen"
#define XML_HIDEANIM "hideAnimation"
#define XML_HIDETIME "hideDelay"
#define XML_HIDESPEED "hideSpeed"
#define XML_LANGUAGE "language"
#define XML_MONITOR "monitor"
#define XML_NOTIFYICON "notifyIcon"
#define XML_ONTOP "onTop"
#define XML_OSD_OFFSET "osdEdgeOffset"
#define XML_OSD_POS "osdPosition"
#define XML_OSD_X "osdX"
#define XML_OSD_Y "osdY"
#define XML_SKIN "skin"
#define XML_SOUNDS "soundEffects"

std::wstring Settings::_appDir(L"");
Settings *Settings::instance;

std::vector<std::wstring> Settings::OSDPosNames = {
    L"top",
    L"left",
    L"right",
    L"bottom",
    L"center",
    L"top-left",
    L"top-right",
    L"bottom-left",
    L"bottom-right",
    L"custom"
};

Settings *Settings::Instance() {
    if (instance == NULL) {
        instance = new Settings();
    }
    return instance;
}

void Settings::Load() {
    _file = AppDir() + L"\\Settings.xml";
    CLOG(L"Loading settings: %s", _file.c_str());

    std::string u8FileName = StringUtils::Narrow(_file);
    tinyxml2::XMLError result = _xml.LoadFile(u8FileName.c_str());
    if (result != tinyxml2::XMLError::XML_SUCCESS) {
        throw std::runtime_error("Failed to parse XML file");
    }

    _root = _xml.GetDocument()->FirstChildElement("settings");
    if (_root == NULL) {
        throw std::runtime_error("Could not find root XML element");
    }
}

int Settings::Save() {
    FILE *stream;
    errno_t err = _wfopen_s(&stream, _file.c_str(), L"w");
    if (err != 0 || stream == NULL) {
        CLOG(L"Could not open settings file for writing!");
        return 100 + err;
    }
    tinyxml2::XMLError result = _xml.SaveFile(stream);
    fclose(stream);
    return result;
}

std::wstring Settings::AppDir() {
    if (_appDir.empty()) {
        wchar_t path[MAX_PATH] = { 0 };
        GetModuleFileName(NULL, path, MAX_PATH);
        PathRemoveFileSpec(path);
        _appDir = std::wstring(path);
    }
    return _appDir;
}

std::wstring Settings::SkinDir() {
    return AppDir() + L"\\" + SKIN_DIR;
}

std::wstring Settings::SettingsApp() {
    return Settings::AppDir() + L"\\" + SETTINGS_APP;
}

std::wstring Settings::LanguagesDir() {
    return AppDir() + L"\\" + LANG_DIR;
}

void Settings::LaunchSettingsApp() {
    std::wstring app = SettingsApp();

    CLOG(L"Opening Settings App: %s", app.c_str());
    int exec = (int) ShellExecute(
        NULL, L"open", app.c_str(), NULL, NULL, SW_SHOWNORMAL);

    if (exec <= 32) {
        Error::ErrorMessage(GENERR_NOTFOUND, app);
    }
}

std::wstring Settings::AudioDeviceID() {
    return GetText(XML_AUDIODEV);
}

std::wstring Settings::LanguageName() {
    std::wstring lang = GetText(XML_LANGUAGE);

    if (lang == L"") {
        return DEFAULT_LANGUAGE;
    } else {
        return lang;
    }
}

bool Settings::AlwaysOnTop() {
    return GetEnabled(XML_ONTOP);
}

void Settings::AlwaysOnTop(bool enable) {
    SetEnabled(XML_ONTOP, enable);
}

bool Settings::HideFullscreen() {
    return GetEnabled(XML_HIDE_WHENFULL);
}

void Settings::HideFullscreen(bool enable) {
    SetEnabled(XML_HIDE_WHENFULL, enable);
}

std::wstring Settings::Monitor() {
    return GetText(XML_MONITOR);
}

void Settings::Monitor(std::wstring monitorName) {
    SetText(XML_MONITOR, StringUtils::Narrow(monitorName));
}

int Settings::OSDEdgeOffset() {
    if (HasSetting(XML_OSD_OFFSET)) {
        return GetInt(XML_OSD_OFFSET);
    } else {
        return DEFAULT_OSD_OFFSET;
    }
}

void Settings::OSDEdgeOffset(int offset) {
    SetInt(XML_OSD_OFFSET, offset);
}

Settings::OSDPos Settings::OSDPosition() {
    std::wstring pos = GetText(XML_OSD_POS);
    std::transform(pos.begin(), pos.end(), pos.begin(), ::tolower);

    for (unsigned int i = 0; i < OSDPosNames.size(); ++i) {
        if (pos == OSDPosNames[i]) {
            return (Settings::OSDPos) i;
        }
    }

    return DEFAULT_OSD_POS;
}

void Settings::OSDPosition(OSDPos pos) {
    std::wstring posStr = OSDPosNames[(int) pos];
    SetText(XML_OSD_POS, StringUtils::Narrow(posStr));
}

int Settings::OSDX() {
    return GetInt(XML_OSD_X);
}

void Settings::OSDX(int x) {
    SetInt(XML_OSD_X, x);
}

int Settings::OSDY() {
    return GetInt(XML_OSD_Y);
}

void Settings::OSDY(int y) {
    SetInt(XML_OSD_Y, y);
}

AnimationTypes::HideAnimation Settings::HideAnim() {
    std::wstring anim = GetText(XML_HIDEANIM);
    std::transform(anim.begin(), anim.end(), anim.begin(), ::tolower);

    std::vector<std::wstring> *names = &AnimationTypes::HideAnimationNames;
    for (unsigned int i = 0; i < names->size(); ++i) {
        if (anim == (*names)[i]) {
            return (AnimationTypes::HideAnimation) i;
        }
    }

    return DEFAULT_HIDE_ANIM;
}

void Settings::HideAnim(AnimationTypes::HideAnimation anim) {
    std::wstring hideStr = AnimationTypes::HideAnimationNames[(int) anim];
    SetText(XML_HIDEANIM, StringUtils::Narrow(hideStr));
}

int Settings::HideDelay() {
    return GetInt(XML_HIDETIME);
}

void Settings::HideDelay(int delay) {
    SetInt(XML_HIDETIME, delay);
}

int Settings::HideSpeed() {
    return GetInt(XML_HIDESPEED);
}

void Settings::HideSpeed(int speed) {
    SetInt(XML_HIDESPEED, speed);
}

bool Settings::CurrentSkin(std::wstring skinName) {
    std::string name = StringUtils::Narrow(skinName);
    std::wstring xml = SkinXML(skinName);
    if (PathFileExists(xml.c_str()) == FALSE) {
        return false;
    }

    SetText(XML_SKIN, name);
    return true;
}

std::wstring Settings::CurrentSkin() {
    std::wstring name = GetText("skin");

    if (name == L"") {
        return DEFAULT_SKIN;
    } else {
        return name;
    }
}

std::wstring Settings::SkinXML() {
    return SkinXML(CurrentSkin());
}

std::wstring Settings::SkinXML(std::wstring skinName) {
    std::wstring skinXML = Settings::AppDir() + L"\\" + SKINS_DIR L"\\"
        + skinName + L"\\" SKIN_XML;
    return skinXML;
}

std::unordered_map<int, HotkeyInfo> Settings::Hotkeys() {
    std::unordered_map<int, HotkeyInfo> keyMappings;

    tinyxml2::XMLElement *hotkeys = _root->FirstChildElement("hotkeys");
    if (hotkeys == NULL) {
        return keyMappings;
    }

    tinyxml2::XMLElement *hotkey = hotkeys->FirstChildElement("hotkey");
    for (; hotkey != NULL; hotkey = hotkey->NextSiblingElement()) {
        int action = -1;
        hotkey->QueryIntAttribute("action", &action);
        if (action == -1) {
            CLOG(L"No action provided for hotkey; skipping");
            continue;
        }

        int combination = -1;
        hotkey->QueryIntAttribute("combination", &combination);
        if (combination == -1) {
            CLOG(L"No key combination provided for hotkey; skipping");
            continue;
        }

        HotkeyInfo hki;
        hki.action = action;
        hki.keyCombination = combination;

        /* Does this hotkey action have any arguments? */
        tinyxml2::XMLElement *arg = hotkey->FirstChildElement("arg");
        for (; arg != NULL; arg = arg->NextSiblingElement()) {
            const char *argStr = arg->GetText();
            hki.args.push_back(StringUtils::Widen(argStr));
        }

        /* Whew, we made it! */
        CLOG(L"%s", hki.ToString().c_str());
        keyMappings[combination] = hki;
    }

    return keyMappings;
}

void Settings::Hotkeys(std::vector<HotkeyInfo> hotkeys) {
    tinyxml2::XMLElement *hkElem = GetOrCreateElement("hotkeys");
    hkElem->DeleteChildren();

    for (HotkeyInfo hotkey : hotkeys) {
        tinyxml2::XMLElement *hk = _xml.NewElement("hotkey");

        hk->SetAttribute("combination", hotkey.keyCombination);
        hk->SetAttribute("action", hotkey.action);

        if (hotkey.args.size() > 0) {
            for (std::wstring arg : hotkey.args) {
                tinyxml2::XMLElement *argElem = _xml.NewElement("arg");
                argElem->SetText(StringUtils::Narrow(arg).c_str());
                hk->InsertEndChild(argElem);
            }
        }

        hkElem->InsertEndChild(hk);
    }
}

bool Settings::NotifyIconEnabled() {
    return GetEnabled(XML_NOTIFYICON);
}

void Settings::NotifyIconEnabled(bool enable) {
    SetEnabled(XML_NOTIFYICON, enable);
}

bool Settings::SoundEffectsEnabled() {
    return GetEnabled(XML_SOUNDS);
}

void Settings::SoundEffectsEnabled(bool enable) {
    SetEnabled(XML_SOUNDS, enable);
}

bool Settings::HasSetting(std::string elementName) {
    tinyxml2::XMLElement *el = _root->FirstChildElement(elementName.c_str());
    return (el != NULL);
}

bool Settings::GetEnabled(std::string elementName) {
    tinyxml2::XMLElement *el = _root->FirstChildElement(elementName.c_str());
    if (el == NULL) {
        std::wstring elStr = StringUtils::Widen(elementName);
        CLOG(L"Warning: XML element '%s' not found", elStr.c_str());
        return false;
    } else {
        bool val = false;
        el->QueryBoolText(&val);
        return val;
    }
}

void Settings::SetEnabled(std::string elementName, bool enabled) {
    tinyxml2::XMLElement *el = GetOrCreateElement(elementName);
    el->SetText(enabled ? "true" : "false");
}

std::wstring Settings::GetText(std::string elementName) {
    tinyxml2::XMLElement *el = _root->FirstChildElement(elementName.c_str());
    if (el == NULL) {
        CLOG(L"Warning: XML element %s not found",
            StringUtils::Widen(elementName).c_str());
        return L"";
    }

    const char* str = el->GetText();
    if (str == NULL) {
        return L"";
    } else {
        return StringUtils::Widen(str);
    }
}

void Settings::SetText(std::string elementName, std::string text) {
    tinyxml2::XMLElement *el = GetOrCreateElement(elementName);
    el->SetText(text.c_str());
}

int Settings::GetInt(std::string elementName) {
    tinyxml2::XMLElement *el = _root->FirstChildElement(elementName.c_str());
    if (el == NULL) {
        std::wstring elStr = StringUtils::Widen(elementName);
        CLOG(L"Warning: XML element '%s' not found", elStr.c_str());
        return 0;
    }

    int val = 0;
    el->QueryIntText(&val);
    return val;
}

void Settings::SetInt(std::string elementName, int value) {
    tinyxml2::XMLElement *el = GetOrCreateElement(elementName);
    el->SetText(value);
}

tinyxml2::XMLElement *Settings::GetOrCreateElement(std::string elementName) {
    tinyxml2::XMLElement *el = _root->FirstChildElement(elementName.c_str());
    if (el == NULL) {
        el = _xml.NewElement(elementName.c_str());
        _root->InsertEndChild(el);
    }
    return el;
}<|endoftext|>