<commit_before>/*
 * Copyright (c) 2011, The University of Oxford
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 * 3. Neither the name of the University of Oxford nor the names of its
 *    contributors may be used to endorse or promote products derived from this
 *    software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include "apps/lib/oskar_settings_load_image.h"

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <QtCore/QSettings>
#include <QtCore/QByteArray>
#include <QtCore/QVariant>
#include <QtCore/QFile>

extern "C"
int oskar_settings_load_image(oskar_SettingsImage* im,
        const char* filename)
{
    QString temp;
    QByteArray t;
    QSettings s(QString(filename), QSettings::IniFormat);
    s.beginGroup("image");

    im->fov_deg = s.value("fov_deg", 2).toDouble();
    im->size = s.value("size", 256).toInt();

    im->channel_snapshots = s.value("channel_snapshots", true).toBool();
    im->channel_range[0] = s.value("channel_start", 0).toInt();
    temp = s.value("channel_end", "max").toString();
    if (temp.compare("max", Qt::CaseInsensitive) == 0)
        im->channel_range[1] = -1;
    else
        im->channel_range[1] = temp.toInt();

    im->time_snapshots = s.value("time_snapshots", true).toBool();
    im->time_range[0] = s.value("time_start", 0).toInt();
    temp = s.value("time_end", "max").toString();
    if (temp.compare("max", Qt::CaseInsensitive) == 0)
        im->time_range[1] = -1;
    else
        im->time_range[1] = temp.toInt();

    temp = s.value("image_type", "I").toString().toUpper();
    QString type(temp);
    if (temp.startsWith("STOKES"))
    {
        im->image_type = OSKAR_IMAGE_TYPE_STOKES;
        type = "STOKES";
    }
    else if (temp == "I")
        im->image_type = OSKAR_IMAGE_TYPE_STOKES_I;
    else if (temp == "Q")
        im->image_type = OSKAR_IMAGE_TYPE_STOKES_Q;
    else if (temp == "U")
        im->image_type = OSKAR_IMAGE_TYPE_STOKES_U;
    else if (temp == "V")
        im->image_type = OSKAR_IMAGE_TYPE_STOKES_V;
    else if (temp.startsWith("LINEAR"))
    {
        im->image_type = OSKAR_IMAGE_TYPE_POL_LINEAR;
        type = "LINEAR";
    }
    else if (temp == "XX")
        im->image_type = OSKAR_IMAGE_TYPE_POL_XX;
    else if (temp == "XY")
        im->image_type = OSKAR_IMAGE_TYPE_POL_XY;
    else if (temp == "YX")
        im->image_type = OSKAR_IMAGE_TYPE_POL_YX;
    else if (temp == "YY")
        im->image_type = OSKAR_IMAGE_TYPE_POL_YY;
    else if (temp == "PSF")
        im->image_type = OSKAR_IMAGE_TYPE_PSF;
    else
        return OSKAR_ERR_SETTINGS_IMAGE;

    temp = s.value("transform_type", "DFT 2D").toString().toUpper();
    if (temp == "DFT 2D")
        im->transform_type = OSKAR_IMAGE_DFT_2D;
    else if (temp == "DFT 3D")
        im->transform_type = OSKAR_IMAGE_DFT_3D;
    else if (temp == "FFT")
        im->transform_type = OSKAR_IMAGE_FFT;
    else
        return OSKAR_ERR_SETTINGS_IMAGE;

    temp = s.value("direction", "Observation pointing direction").toString();
    if (temp.startsWith("O", Qt::CaseInsensitive))
        im->direction_type = OSKAR_IMAGE_DIRECTION_OBSERVATION;
    else if (temp.startsWith("R", Qt::CaseInsensitive))
        im->direction_type = OSKAR_IMAGE_DIRECTION_RA_DEC;
    else
        return OSKAR_ERR_SETTINGS_IMAGE;

    im->ra_deg  = s.value("direction/ra_deg", 0.0).toDouble();
    im->dec_deg = s.value("direction/dec_deg", 0.0).toDouble();

    t = s.value("input_vis_data").toByteArray();
    if (t.size() > 0)
    {
        im->input_vis_data = (char*)malloc(t.size() + 1);
        strcpy(im->input_vis_data, t.constData());
    }

    bool overwrite = s.value("overwrite", true).toBool();
    t = s.value("root").toByteArray();
    if (t.size() > 0)
    {
        t += "_" + type;
        // Construct FITS filename
        if (s.value("fits_image", true).toBool())
        {
            if (!overwrite)
            {
                if (QFile::exists(QString(t) + ".fits"))
                {
                    int i = 1;
                    while (true)
                    {
                        QString test = QString(t) + "-" + QString::number(i);
                        test += ".fits";
                        if (!QFile::exists(QString(test)))
                        {
                            t = test.toAscii();
                            break;
                        }
                        ++i;
                    }
                }
            }
            else
            {
                t += ".fits";
            }
            im->fits_image = (char*)malloc(t.size() + 1);
            strcpy(im->fits_image, t.constData());
        }
        // Construct OSKAR filename
        if (s.value("oskar_image", false).toBool())
        {
            if (!overwrite)
            {
                if (QFile::exists(QString(t) + ".img"))
                {
                    int i = 1;
                    while (true)
                    {
                        QString test = QString(t) + "-" + QString::number(i);
                        test += ".fits";
                        if (!QFile::exists(QString(test)))
                        {
                            t = test.toAscii();
                            break;
                        }
                        ++i;
                    }
                }
            }
            else
            {
                t += ".img";
            }
            im->oskar_image = (char*)malloc(t.size() + 1);
            strcpy(im->oskar_image, t.constData());
        }
    }

#if 0
    t = s.value("oskar_image_root").toByteArray();
    if (t.size() > 0)
    {
        // Construct filename from root.
        t += "_" + type + ".img";
        im->oskar_image = (char*)malloc(t.size() + 1);
        strcpy(im->oskar_image, t.constData());
    }

    t = s.value("fits_image_root").toByteArray();
    if (t.size() > 0)
    {
        t += "_" + type + ".fits";
        im->fits_image = (char*)malloc(t.size() + 1);
        strcpy(im->fits_image, t.constData());
    }
#endif

    return OSKAR_SUCCESS;
}
<commit_msg>fixed bug in output image name creation<commit_after>/*
 * Copyright (c) 2011, The University of Oxford
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 * 3. Neither the name of the University of Oxford nor the names of its
 *    contributors may be used to endorse or promote products derived from this
 *    software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include "apps/lib/oskar_settings_load_image.h"

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <QtCore/QSettings>
#include <QtCore/QByteArray>
#include <QtCore/QVariant>
#include <QtCore/QFile>

extern "C"
int oskar_settings_load_image(oskar_SettingsImage* im,
        const char* filename)
{
    QString temp;
    QByteArray t;
    QSettings s(QString(filename), QSettings::IniFormat);
    s.beginGroup("image");

    im->fov_deg = s.value("fov_deg", 2).toDouble();
    im->size = s.value("size", 256).toInt();

    im->channel_snapshots = s.value("channel_snapshots", true).toBool();
    im->channel_range[0] = s.value("channel_start", 0).toInt();
    temp = s.value("channel_end", "max").toString();
    if (temp.compare("max", Qt::CaseInsensitive) == 0)
        im->channel_range[1] = -1;
    else
        im->channel_range[1] = temp.toInt();

    im->time_snapshots = s.value("time_snapshots", true).toBool();
    im->time_range[0] = s.value("time_start", 0).toInt();
    temp = s.value("time_end", "max").toString();
    if (temp.compare("max", Qt::CaseInsensitive) == 0)
        im->time_range[1] = -1;
    else
        im->time_range[1] = temp.toInt();

    temp = s.value("image_type", "I").toString().toUpper();
    QString type(temp);
    if (temp.startsWith("STOKES"))
    {
        im->image_type = OSKAR_IMAGE_TYPE_STOKES;
        type = "STOKES";
    }
    else if (temp == "I")
        im->image_type = OSKAR_IMAGE_TYPE_STOKES_I;
    else if (temp == "Q")
        im->image_type = OSKAR_IMAGE_TYPE_STOKES_Q;
    else if (temp == "U")
        im->image_type = OSKAR_IMAGE_TYPE_STOKES_U;
    else if (temp == "V")
        im->image_type = OSKAR_IMAGE_TYPE_STOKES_V;
    else if (temp.startsWith("LINEAR"))
    {
        im->image_type = OSKAR_IMAGE_TYPE_POL_LINEAR;
        type = "LINEAR";
    }
    else if (temp == "XX")
        im->image_type = OSKAR_IMAGE_TYPE_POL_XX;
    else if (temp == "XY")
        im->image_type = OSKAR_IMAGE_TYPE_POL_XY;
    else if (temp == "YX")
        im->image_type = OSKAR_IMAGE_TYPE_POL_YX;
    else if (temp == "YY")
        im->image_type = OSKAR_IMAGE_TYPE_POL_YY;
    else if (temp == "PSF")
        im->image_type = OSKAR_IMAGE_TYPE_PSF;
    else
        return OSKAR_ERR_SETTINGS_IMAGE;

    temp = s.value("transform_type", "DFT 2D").toString().toUpper();
    if (temp == "DFT 2D")
        im->transform_type = OSKAR_IMAGE_DFT_2D;
    else if (temp == "DFT 3D")
        im->transform_type = OSKAR_IMAGE_DFT_3D;
    else if (temp == "FFT")
        im->transform_type = OSKAR_IMAGE_FFT;
    else
        return OSKAR_ERR_SETTINGS_IMAGE;

    temp = s.value("direction", "Observation pointing direction").toString();
    if (temp.startsWith("O", Qt::CaseInsensitive))
        im->direction_type = OSKAR_IMAGE_DIRECTION_OBSERVATION;
    else if (temp.startsWith("R", Qt::CaseInsensitive))
        im->direction_type = OSKAR_IMAGE_DIRECTION_RA_DEC;
    else
        return OSKAR_ERR_SETTINGS_IMAGE;

    im->ra_deg  = s.value("direction/ra_deg", 0.0).toDouble();
    im->dec_deg = s.value("direction/dec_deg", 0.0).toDouble();

    t = s.value("input_vis_data").toByteArray();
    if (t.size() > 0)
    {
        im->input_vis_data = (char*)malloc(t.size() + 1);
        strcpy(im->input_vis_data, t.constData());
    }

    bool overwrite = s.value("overwrite", true).toBool();
    t = s.value("root").toByteArray();
    if (t.size() > 0)
    {
        t += "_" + type;
        // Construct FITS filename
        if (s.value("fits_image", true).toBool())
        {
            if (!overwrite && QFile::exists(QString(t) + ".fits"))
            {
                int i = 1;
                while (true)
                {
                    QString test = QString(t) + "-" + QString::number(i);
                    test += ".fits";
                    if (!QFile::exists(QString(test)))
                    {
                        t = test.toAscii();
                        break;
                    }
                    ++i;
                }
            }
            else
            {
                t += ".fits";
            }
            im->fits_image = (char*)malloc(t.size() + 1);
            strcpy(im->fits_image, t.constData());
        }
        // Construct OSKAR filename
        if (s.value("oskar_image", false).toBool())
        {
            if (!overwrite && QFile::exists(QString(t) + ".img"))
            {
                int i = 1;
                while (true)
                {
                    QString test = QString(t) + "-" + QString::number(i);
                    test += ".fits";
                    if (!QFile::exists(QString(test)))
                    {
                        t = test.toAscii();
                        break;
                    }
                    ++i;
                }
            }
            else
            {
                t += ".img";
            }
            im->oskar_image = (char*)malloc(t.size() + 1);
            strcpy(im->oskar_image, t.constData());
        }
    }

#if 0
    t = s.value("oskar_image_root").toByteArray();
    if (t.size() > 0)
    {
        // Construct filename from root.
        t += "_" + type + ".img";
        im->oskar_image = (char*)malloc(t.size() + 1);
        strcpy(im->oskar_image, t.constData());
    }

    t = s.value("fits_image_root").toByteArray();
    if (t.size() > 0)
    {
        t += "_" + type + ".fits";
        im->fits_image = (char*)malloc(t.size() + 1);
        strcpy(im->fits_image, t.constData());
    }
#endif

    return OSKAR_SUCCESS;
}
<|endoftext|>


<commit_before>#include "ShotSegmentation.hpp"

ShotSegmentation::ShotSegmentation(vector<Mat> histograms) {
	this->histograms = histograms;
}

void ShotSegmentation::setGradualThreshold(int value) {
	this->gradualHeuristicThreshold = value;
}

void ShotSegmentation::setSlidingWindowsIntersect(float value) {
	this->swIntersectThreshold = value;
}

void ShotSegmentation::setSlidingWindowsEuclidean(float value) {
	this->swEuclideanThreshold = value;
}

void ShotSegmentation::setLocalSlidingWindowIntersect(float value) {
	this->localSlidingWindowIntersectThreshold = value;
}

void ShotSegmentation::setLocalSlidingWindowEuclidean(float value) {
	this->localSlidingWindowEuclideanThreshold = value;
}

double ShotSegmentation::histogramEuclideanDistance(Mat histogram1, Mat histogram2) {
	double distance = 0.0;
	for(int h = 0; h < 8; h++) {
		for(int s = 0; s < 4; s++) {
			for(int v = 0; v < 4; v++) {
				float val1 = histogram1.at<float>(h,s,v);
				float val2 = histogram2.at<float>(h,s,v);
				distance = distance + sqrt(pow(val1-val2,2.0));
			}
		}
	}
	return distance;
}

double ShotSegmentation::histogramIntersectionDistance(Mat histogram1, Mat histogram2) {
	return compareHist(histogram1, histogram2, CV_COMP_INTERSECT);
}

double ShotSegmentation::calcThresholdIntersection(vector<double> distances, pair<int,int> window) {
	double avg = 0.0;

	for(int i = window.first; i < window.second; i++) {
		avg = avg + distances[i];
	}
	avg = avg / (double) (window.second - window.first);

	return avg * this->localSlidingWindowIntersectThreshold;
}

double ShotSegmentation::calcThresholdEuclidean(vector<double> distances, pair<int,int> window) {
	double avg = 0.0;

	for(int i = window.first; i < window.second; i++) {
		avg = avg + distances[i];
	}
	avg = avg / (double) (window.second - window.first);
	return avg * this->localSlidingWindowEuclideanThreshold;
}

bool ShotSegmentation::heuristicIntersec(vector<double> distances, int pos, double threshold) {
	for(int i = pos; i < pos+this->gradualHeuristicThreshold && i < distances.size(); i++) {
		if(distances[i] < threshold) {
			return true;
		}
	}
	return false;
}

bool ShotSegmentation::heuristicEuclidean(vector<double> distances, int pos, double threshold) {
	for(int i = pos; i < pos+this->gradualHeuristicThreshold && i < distances.size(); i++) {
		if(distances[i] > threshold) {
			return true;
		}
	}
	return false;
}

vector< pair<int,int> > ShotSegmentation::segmentSlidingWindows(vector<double> distEuclidean, vector<double> distIntersec, double thresholdIntersec, double thresholdEuclidean, pair<int,int> window) {
	int i, j, ant;
	vector< pair<int,int> > shots;
	for(ant = window.first, i = window.first, j = 0; i < window.second; i++) {
		if(distIntersec[i] <= thresholdIntersec || distEuclidean[i] >= thresholdEuclidean) {
			j++;
		} else {
			if (j > 0) {
				if(heuristicIntersec(distIntersec, i, thresholdIntersec) || heuristicEuclidean(distEuclidean, i, thresholdEuclidean)) {
					j++;
				} else {
					if (j >= 1) {
						shots.push_back(make_pair(ant,i - j));
						ant = i - j + 1;
					}
					j = 0;
				}
			}
		}
	}
	shots.push_back(make_pair(ant,window.second));
	return shots;
}

vector< pair<int,int> > ShotSegmentation::segment() {
	vector<double> distEuclidean, distIntersec, thresholdIntersec, thresholdEuclidean;
	vector<double>::iterator maxVal, minVal;
	int previousPos = 0;
	vector<pair<int,int> > slidingWindow;
	pair<int,int> window;

	/* Calculate the distances between consecutive histograms*/
	for(int i = 1; i < this->histograms.size(); i++) {
		distEuclidean.push_back(this->histogramEuclideanDistance(this->histograms[i-1],this->histograms[i]));
		distIntersec.push_back(this->histogramIntersectionDistance(this->histograms[i-1],this->histograms[i]));
	}

	/* Find the max and min distances among the histograms */
	maxVal = max_element(distEuclidean.begin(), distEuclidean.end());
	minVal = min_element(distIntersec.begin(), distIntersec.end());

	/* Generate the sliding windows and its threholds */
	int i;
	for(i = 0; i < distIntersec.size(); i++) {
		if(distIntersec[i] <= this->swIntersectThreshold || (distIntersec[i] <= (*minVal * 1.5) && distIntersec[i] <= 0.4) ||
		   (distEuclidean[i] >= (*maxVal * 0.85) && distEuclidean[i] >= 0.9) || distEuclidean[i] >= this->swEuclideanThreshold ) {
			   window = make_pair(previousPos,i);
			   thresholdIntersec.push_back(this->calcThresholdIntersection(distIntersec, window));
			   thresholdEuclidean.push_back(this->calcThresholdEuclidean(distEuclidean, window));
			   slidingWindow.push_back(window);
			   previousPos = i+1;
		   }
	}
	if(previousPos < distIntersec.size() && i <= distIntersec.size() && slidingWindow.size() > 0) {
		window = make_pair(previousPos,i);
		thresholdIntersec.push_back(this->calcThresholdIntersection(distIntersec, window));
		thresholdEuclidean.push_back(this->calcThresholdEuclidean(distEuclidean, window));
		slidingWindow.push_back(window);
	} else if (slidingWindow.size() == 0) {
		window = make_pair(0,distIntersec.size()-1);
		thresholdIntersec.push_back(this->calcThresholdIntersection(distIntersec, window));
		thresholdEuclidean.push_back(this->calcThresholdEuclidean(distEuclidean, window));
		slidingWindow.push_back(window);
	}

	/* Do the shot segmentation for each sliding window */
	vector< pair<int,int> > shots;
	for(int i = 0; i < slidingWindow.size(); i++) {
		vector< pair<int,int> > temp = this->segmentSlidingWindows(distEuclidean, distIntersec, thresholdIntersec[i], thresholdEuclidean[i], slidingWindow[i]);
		shots.insert(shots.end(), temp.begin(), temp.end());
	}

	/* Remove all shots with a duration of 1 frame or less */
	for(int i = 0; i < shots.size(); i++) {
		if(shots[i].second - shots[i].first <= 1) {
			shots.erase(shots.begin() + i);
			i--;
		}
	}

	/* Increase all values by 1. The first frame should begin with 1 :) */
	for(int i = 0; i < shots.size(); i++) {
		shots[i] = make_pair(shots[i].first+1, shots[i].second+1);
	}

	return shots;
}<commit_msg>Fixes #2. Also fixed intersection and euclidean distances heuristic thresholds which were not being properly used<commit_after>#include "ShotSegmentation.hpp"

ShotSegmentation::ShotSegmentation(vector<Mat> histograms) {
	this->histograms = histograms;
}

void ShotSegmentation::setGradualThreshold(int value) {
	this->gradualHeuristicThreshold = value;
}

void ShotSegmentation::setSlidingWindowsIntersect(float value) {
	this->swIntersectThreshold = value;
}

void ShotSegmentation::setSlidingWindowsEuclidean(float value) {
	this->swEuclideanThreshold = value;
}

void ShotSegmentation::setLocalSlidingWindowIntersect(float value) {
	this->localSlidingWindowIntersectThreshold = value;
}

void ShotSegmentation::setLocalSlidingWindowEuclidean(float value) {
	this->localSlidingWindowEuclideanThreshold = value;
}

double ShotSegmentation::histogramEuclideanDistance(Mat histogram1, Mat histogram2) {
	double distance = 0.0;
	for(int h = 0; h < 8; h++) {
		for(int s = 0; s < 4; s++) {
			for(int v = 0; v < 4; v++) {
				float val1 = histogram1.at<float>(h,s,v);
				float val2 = histogram2.at<float>(h,s,v);
				distance = distance + sqrt(pow(val1-val2,2.0));
			}
		}
	}
	return distance;
}

double ShotSegmentation::histogramIntersectionDistance(Mat histogram1, Mat histogram2) {
	return compareHist(histogram1, histogram2, CV_COMP_INTERSECT);
}

double ShotSegmentation::calcThresholdIntersection(vector<double> distances, pair<int,int> window) {
	double avg = 0.0;

	for(int i = window.first; i < window.second; i++) {
		avg = avg + distances[i];
	}
	avg = avg / (double) (window.second - window.first);

	return avg * this->swIntersectThreshold;
}

double ShotSegmentation::calcThresholdEuclidean(vector<double> distances, pair<int,int> window) {
	double avg = 0.0;

	for(int i = window.first; i < window.second; i++) {
		avg = avg + distances[i];
	}
	avg = avg / (double) (window.second - window.first);
	return avg * this->swEuclideanThreshold;
}

bool ShotSegmentation::heuristicIntersec(vector<double> distances, int pos, double threshold) {
	for(int i = pos; i <= pos+this->gradualHeuristicThreshold && i < distances.size(); i++) {
		if(distances[i] < threshold) {
			return true;
		}
	}
	return false;
}

bool ShotSegmentation::heuristicEuclidean(vector<double> distances, int pos, double threshold) {
	for(int i = pos; i <= pos+this->gradualHeuristicThreshold && i < distances.size(); i++) {
		if(distances[i] > threshold) {
			return true;
		}
	}
	return false;
}

vector< pair<int,int> > ShotSegmentation::segmentSlidingWindows(vector<double> distEuclidean, vector<double> distIntersec, double thresholdIntersec, double thresholdEuclidean, pair<int,int> window) {
	int actual, gradual, ant;
	vector< pair<int,int> > shots;
	for(ant = window.first, actual = window.first, gradual = 0; actual < window.second; actual++) {
		/* The frame is a transition */
		if(distIntersec[actual] <= thresholdIntersec || distEuclidean[actual] >= thresholdEuclidean) {
			gradual++;
		} else {
			/* The frame is not a transition, but there was a transition before it */
			if (gradual > 0) {
				/* There is a very close frame transition after it*/
				if(heuristicIntersec(distIntersec, actual, thresholdIntersec) || heuristicEuclidean(distEuclidean, actual, thresholdEuclidean)) {
					gradual++;
				} else {
					shots.push_back(make_pair(ant, actual - gradual));
					/* As this frame is not a transition, it is the begining of a new shot. So reset the relevant values */
					ant = actual;
					gradual = 0;
				}
			}
		}
	}
	/* The very last shot of the local is also a shot so add it. But only if its not a part of a gradual transition... */
	if(shots.size() > 0 && shots[shots.size()-1].second != window.second && gradual == 0) {
		shots.push_back(make_pair(shots[shots.size()-1].second+1,window.second));
	}

	return shots;
}

vector< pair<int,int> > ShotSegmentation::segment() {
	vector<double> distEuclidean, distIntersec, thresholdIntersec, thresholdEuclidean;
	vector<double>::iterator maxVal, minVal;
	int previousPos = 0;
	vector<pair<int,int> > slidingWindow;
	pair<int,int> window;

	/* Calculate the distances between consecutive histograms*/
	for(int i = 1; i < this->histograms.size(); i++) {
		distEuclidean.push_back(this->histogramEuclideanDistance(this->histograms[i-1],this->histograms[i]));
		distIntersec.push_back(this->histogramIntersectionDistance(this->histograms[i-1],this->histograms[i]));
	}

	/* Find the max and min distances among the histograms */
	maxVal = max_element(distEuclidean.begin(), distEuclidean.end());
	minVal = min_element(distIntersec.begin(), distIntersec.end());

	/* Generate the sliding windows and its threholds */
	int i;
	for(i = 0; i < distIntersec.size(); i++) {
		if(distIntersec[i] <= this->swIntersectThreshold || (distIntersec[i] <= (*minVal * 1.5) && distIntersec[i] <= 0.4) ||
		   (distEuclidean[i] >= (*maxVal * 0.85) && distEuclidean[i] >= 0.9) || distEuclidean[i] >= this->swEuclideanThreshold ) {
			   window = make_pair(previousPos,i);
			   thresholdIntersec.push_back(this->calcThresholdIntersection(distIntersec, window));
			   thresholdEuclidean.push_back(this->calcThresholdEuclidean(distEuclidean, window));
			   slidingWindow.push_back(window);
			   previousPos = i+1;
		   }
	}
	if(previousPos < distIntersec.size() && i <= distIntersec.size() && slidingWindow.size() > 0) {
		window = make_pair(previousPos,i);
		thresholdIntersec.push_back(this->calcThresholdIntersection(distIntersec, window));
		thresholdEuclidean.push_back(this->calcThresholdEuclidean(distEuclidean, window));
		slidingWindow.push_back(window);
	} else if (slidingWindow.size() == 0) {
		window = make_pair(0,distIntersec.size()-1);
		thresholdIntersec.push_back(this->calcThresholdIntersection(distIntersec, window));
		thresholdEuclidean.push_back(this->calcThresholdEuclidean(distEuclidean, window));
		slidingWindow.push_back(window);
	}

	/* Do the shot segmentation for each sliding window */
	vector< pair<int,int> > shots;
	for(int i = 0; i < slidingWindow.size(); i++) {
		vector< pair<int,int> > temp = this->segmentSlidingWindows(distEuclidean, distIntersec, thresholdIntersec[i], thresholdEuclidean[i], slidingWindow[i]);
		shots.insert(shots.end(), temp.begin(), temp.end());
	}

	/* Remove all shots with a duration of 1 frame or less */
	for(int i = 0; i < shots.size(); i++) {
		if(shots[i].second - shots[i].first <= 1) {
			shots.erase(shots.begin() + i);
			i--;
		}
	}

	/* Increase all values by 1. The first frame should begin with 1 :) */
	for(int i = 0; i < shots.size(); i++) {
		shots[i] = make_pair(shots[i].first+1, shots[i].second+1);
	}

	return shots;
}<|endoftext|>


<commit_before>//2D implementation of the Ramer-Douglas-Peucker algorithm
//https://en.wikipedia.org/wiki/Ramer%E2%80%93Douglas%E2%80%93Peucker_algorithm

#include <iostream>
#include <cmath>
#include <utility>
#include <vector>
#include <stdexcept>
#include "RdpSimplify.h"
using namespace std;

double PerpendicularDistance(const Point &pt, const Point &lineStart, const Point &lineEnd)
{
	double dx = lineEnd.first - lineStart.first;
	double dy = lineEnd.second - lineStart.second;

	//Normalise
	double mag = pow(pow(dx,2.0)+pow(dy,2.0),0.5);
	if(mag > 0.0)
	{
		dx /= mag; dy /= mag;
	}

	double pvx = pt.first - lineStart.first;
	double pvy = pt.second - lineStart.second;

	//Get dot product (project pv onto normalized direction)
	double pvdot = dx * pvx + dy * pvy;

	//Scale line direction vector
	double dsx = pvdot * dx;
	double dsy = pvdot * dy;

	//Subtract this from pv
	double ax = pvx - dsx;
	double ay = pvy - dsy;

	return pow(pow(ax,2.0)+pow(ay,2.0),0.5);
}

void RamerDouglasPeucker(const Contour &pointList, double epsilon, Contour &out)
{
	if(pointList.size()<2)
		throw invalid_argument("Not enough points to simplify");

	// Find the point with the maximum distance from line between start and end
	double dmax = 0.0;
	size_t index = 0;
	size_t end = pointList.size()-1;
	for(size_t i = 1; i < end; i++)
	{
		double d = PerpendicularDistance(pointList[i], pointList[0], pointList[end]);
		if (d > dmax)
		{
			index = i;
			dmax = d;
		}
	}

	// If max distance is greater than epsilon, recursively simplify
	if(dmax > epsilon)
	{
		// Recursive call
		vector<Point> recResults1;
		vector<Point> recResults2;
		vector<Point> firstLine(pointList.begin(), pointList.begin()+index+1);
		vector<Point> lastLine(pointList.begin()+index, pointList.end());
		RamerDouglasPeucker(firstLine, epsilon, recResults1);
		RamerDouglasPeucker(lastLine, epsilon, recResults2);

		// Build the result list
		out.assign(recResults1.begin(), recResults1.end()-1);
		out.insert(out.end(), recResults2.begin(), recResults2.end());
		if(out.size()<2)
			throw runtime_error("Problem assembling output");
	}
	else
	{
		//Just return start and end points
		out.clear();
		out.push_back(pointList[0]);
		out.push_back(pointList[end]);
	}
}

int main()
{
	vector<Point> pointList;
	vector<Point> pointListOut;

	pointList.push_back(Point(0.0, 0.0));
	pointList.push_back(Point(1.0, 0.1));
	pointList.push_back(Point(2.0, -0.1));
	pointList.push_back(Point(3.0, 5.0));
	pointList.push_back(Point(4.0, 6.0));
	pointList.push_back(Point(5.0, 7.0));
	pointList.push_back(Point(6.0, 8.1));
	pointList.push_back(Point(7.0, 9.0));
	pointList.push_back(Point(8.0, 9.0));
	pointList.push_back(Point(9.0, 9.0));

	RamerDouglasPeucker(pointList, 1.0, pointListOut);

	cout << "result" << endl;
	for(size_t i=0;i< pointListOut.size();i++)
	{
		cout << pointListOut[i].first << "," << pointListOut[i].second << endl;
	}

	return 0;
}

<commit_msg>Remove test code<commit_after>//2D implementation of the Ramer-Douglas-Peucker algorithm
//https://en.wikipedia.org/wiki/Ramer%E2%80%93Douglas%E2%80%93Peucker_algorithm

#include <iostream>
#include <cmath>
#include <utility>
#include <vector>
#include <stdexcept>
#include "RdpSimplify.h"
using namespace std;

double PerpendicularDistance(const Point &pt, const Point &lineStart, const Point &lineEnd)
{
	double dx = lineEnd.first - lineStart.first;
	double dy = lineEnd.second - lineStart.second;

	//Normalise
	double mag = pow(pow(dx,2.0)+pow(dy,2.0),0.5);
	if(mag > 0.0)
	{
		dx /= mag; dy /= mag;
	}

	double pvx = pt.first - lineStart.first;
	double pvy = pt.second - lineStart.second;

	//Get dot product (project pv onto normalized direction)
	double pvdot = dx * pvx + dy * pvy;

	//Scale line direction vector
	double dsx = pvdot * dx;
	double dsy = pvdot * dy;

	//Subtract this from pv
	double ax = pvx - dsx;
	double ay = pvy - dsy;

	return pow(pow(ax,2.0)+pow(ay,2.0),0.5);
}

void RamerDouglasPeucker(const Contour &pointList, double epsilon, Contour &out)
{
	if(pointList.size()<2)
		throw invalid_argument("Not enough points to simplify");

	// Find the point with the maximum distance from line between start and end
	double dmax = 0.0;
	size_t index = 0;
	size_t end = pointList.size()-1;
	for(size_t i = 1; i < end; i++)
	{
		double d = PerpendicularDistance(pointList[i], pointList[0], pointList[end]);
		if (d > dmax)
		{
			index = i;
			dmax = d;
		}
	}

	// If max distance is greater than epsilon, recursively simplify
	if(dmax > epsilon)
	{
		// Recursive call
		vector<Point> recResults1;
		vector<Point> recResults2;
		vector<Point> firstLine(pointList.begin(), pointList.begin()+index+1);
		vector<Point> lastLine(pointList.begin()+index, pointList.end());
		RamerDouglasPeucker(firstLine, epsilon, recResults1);
		RamerDouglasPeucker(lastLine, epsilon, recResults2);

		// Build the result list
		out.assign(recResults1.begin(), recResults1.end()-1);
		out.insert(out.end(), recResults2.begin(), recResults2.end());
		if(out.size()<2)
			throw runtime_error("Problem assembling output");
	}
	else
	{
		//Just return start and end points
		out.clear();
		out.push_back(pointList[0]);
		out.push_back(pointList[end]);
	}
}

<|endoftext|>


<commit_before>
// Author:  Greg "fugue" Santucci, 2011
// Email:   thecodewitch@gmail.com
// Web:     http://createuniverses.blogspot.com/

#include "luaCB.h"

int luaCBLuaCall(lua_State * L)
{
    std::string sText = luaL_checkstring(L, 1);

    luaCall(sText);

    return 0;
}

void cbLuaBreakHook(lua_State *L, lua_Debug *ar);

int luaCBTurnOnDebugHook(lua_State * L)
{
    int nLines = 1000;

    int n = lua_gettop(L);
    if(n == 1)
        nLines = luaL_checknumber(L, 1);

    lua_sethook(L, cbLuaBreakHook, LUA_MASKCOUNT, nLines);

    return 0;
}

int luaCBTurnOffDebugHook(lua_State * L)
{
    lua_sethook(L, 0, LUA_MASKCOUNT, 1000);
    return 0;
}

int luaCBGetFPS(lua_State * L)
{
    extern float g_fFPS;
    lua_pushnumber(L, g_fFPS);
    return 1;
}

int luaCBGetCurrentDir(lua_State * L)
{
    return 0;
}

#ifdef __PRAXIS_LINUX__
#include <unistd.h>
int luaCBSetCurrentDir(lua_State * L)
{
    std::string sDir = luaL_checkstring(L, 1);
    chdir(sDir.c_str());
    return 0;
}
#endif

#ifdef __PRAXIS_WINDOWS__
int luaCBSetCurrentDir(lua_State * L)
{
    std::string sDir = luaL_checkstring(L, 1);
    ::SetCurrentDirectory(sDir.c_str());
    return 0;
}
#endif

int luaCBPrintf(lua_State * L)
{
    std::string s = luaL_checkstring(L, 1);
    printf("%s", s.c_str());
    fflush(stdout);
    return 0;
}

int luaCBPlatform(lua_State * L)
{
    std::string s = "undefined";
#ifdef __PRAXIS_WINDOWS__
    s = "windows";
#endif
#ifdef __PRAXIS_LINUX__
    s = "linux";
#endif
    lua_pushstring(L, s.c_str());
    return 1;
}

void luaInitCallbacksSystem()
{
    lua_register(g_pLuaState, "luaCall",               luaCBLuaCall);

    lua_register(g_pLuaState, "turnOnDebugHook",       luaCBTurnOnDebugHook);
    lua_register(g_pLuaState, "turnOffDebugHook",      luaCBTurnOffDebugHook);

    lua_register(g_pLuaState, "getFPS",                luaCBGetFPS);

    lua_register(g_pLuaState, "getCurrentDir",         luaCBGetCurrentDir);
    lua_register(g_pLuaState, "setCurrentDir",         luaCBSetCurrentDir);

    lua_register(g_pLuaState, "printf",                luaCBPrintf);

    lua_register(g_pLuaState, "platform",              luaCBPlatform);
}
<commit_msg>getchar added, because why not!<commit_after>
// Author:  Greg "fugue" Santucci, 2011
// Email:   thecodewitch@gmail.com
// Web:     http://createuniverses.blogspot.com/

#include "luaCB.h"

int luaCBLuaCall(lua_State * L)
{
    std::string sText = luaL_checkstring(L, 1);

    luaCall(sText);

    return 0;
}

void cbLuaBreakHook(lua_State *L, lua_Debug *ar);

int luaCBTurnOnDebugHook(lua_State * L)
{
    int nLines = 1000;

    int n = lua_gettop(L);
    if(n == 1)
        nLines = luaL_checknumber(L, 1);

    lua_sethook(L, cbLuaBreakHook, LUA_MASKCOUNT, nLines);

    return 0;
}

int luaCBTurnOffDebugHook(lua_State * L)
{
    lua_sethook(L, 0, LUA_MASKCOUNT, 1000);
    return 0;
}

int luaCBGetFPS(lua_State * L)
{
    extern float g_fFPS;
    lua_pushnumber(L, g_fFPS);
    return 1;
}

int luaCBGetCurrentDir(lua_State * L)
{
    return 0;
}

#ifdef __PRAXIS_LINUX__
#include <unistd.h>
int luaCBSetCurrentDir(lua_State * L)
{
    std::string sDir = luaL_checkstring(L, 1);
    chdir(sDir.c_str());
    return 0;
}
#endif

#ifdef __PRAXIS_WINDOWS__
int luaCBSetCurrentDir(lua_State * L)
{
    std::string sDir = luaL_checkstring(L, 1);
    ::SetCurrentDirectory(sDir.c_str());
    return 0;
}
#endif

int luaCBPrintf(lua_State * L)
{
    std::string s = luaL_checkstring(L, 1);
    printf("%s", s.c_str());
    fflush(stdout);
    return 0;
}

//#include <conio.h>

int luaCBGetChar(lua_State * L)
{
    int c = getchar();
    //int c = getch();
    lua_pushnumber(L, c);
    return 1;
}

int luaCBPlatform(lua_State * L)
{
    std::string s = "undefined";
#ifdef __PRAXIS_WINDOWS__
    s = "windows";
#endif
#ifdef __PRAXIS_LINUX__
    s = "linux";
#endif
    lua_pushstring(L, s.c_str());
    return 1;
}

void luaInitCallbacksSystem()
{
    lua_register(g_pLuaState, "luaCall",               luaCBLuaCall);

    lua_register(g_pLuaState, "turnOnDebugHook",       luaCBTurnOnDebugHook);
    lua_register(g_pLuaState, "turnOffDebugHook",      luaCBTurnOffDebugHook);

    lua_register(g_pLuaState, "getFPS",                luaCBGetFPS);

    lua_register(g_pLuaState, "getCurrentDir",         luaCBGetCurrentDir);
    lua_register(g_pLuaState, "setCurrentDir",         luaCBSetCurrentDir);

    lua_register(g_pLuaState, "printf",                luaCBPrintf);
    lua_register(g_pLuaState, "getchar",               luaCBGetChar);

    lua_register(g_pLuaState, "platform",              luaCBPlatform);
}
<|endoftext|>


<commit_before>// Copyright © 2016 The Things Network
// Use of this source code is governed by the MIT license that can be found in the LICENSE file.

#include <Arduino.h>
#include <TheThingsNetwork.h>

#define debugPrintLn(...) { if (debugStream) debugStream->println(__VA_ARGS__); }
#define debugPrint(...) { if (debugStream) debugStream->print(__VA_ARGS__); }

String TheThingsNetwork::readLine(int waitTime) {
  unsigned long start = millis();
  while (millis() < start + waitTime) {
    String line = modemStream->readStringUntil('\n');
    if (line.length() > 0) {
      return line.substring(0, line.length() - 1);
    }
  }
  return "";
}

bool TheThingsNetwork::waitForOK(int waitTime, String okMessage) {
  String line = readLine(waitTime);
  if (line == "") {
    debugPrintLn(F("Wait for OK time-out expired"));
    return false;
  }

  if (line != okMessage) {
    debugPrint(F("Response is not OK: "));
    debugPrintLn(line);
    return false;
  }

  return true;
}

String TheThingsNetwork::readValue(String cmd) {
  modemStream->println(cmd);
  return readLine();
}

bool TheThingsNetwork::sendCommand(String cmd, int waitTime) {
  debugPrint(F("Sending: "));
  debugPrintLn(cmd);

  modemStream->println(cmd);

  return waitForOK(waitTime);
}

bool TheThingsNetwork::sendCommand(String cmd, String value, int waitTime) {
  int l = value.length();
  byte buf[l];
  value.getBytes(buf, l);

  return sendCommand(cmd, buf, l, waitTime);
}

char btohexa_high(unsigned char b) {
  b >>= 4;
  return (b > 0x9u) ? b + 'A' - 10 : b + '0';
}

char btohexa_low(unsigned char b) {
  b &= 0x0F;
  return (b > 0x9u) ? b + 'A' - 10 : b + '0';
}

bool TheThingsNetwork::sendCommand(String cmd, const byte *buf, int length, int waitTime) {
  debugPrint(F("Sending: "));
  debugPrint(cmd);
  debugPrint(F(" with "));
  debugPrint(length);
  debugPrintLn(F(" bytes"));

  modemStream->print(cmd + " ");

  for (int i = 0; i < length; i++) {
    modemStream->print(btohexa_high(buf[i]));
    modemStream->print(btohexa_low(buf[i]));
  }
  modemStream->println();

  return waitForOK(waitTime);
}

void TheThingsNetwork::reset(bool adr) {
  #if !TTN_ADR_SUPPORTED
    adr = false;
  #endif

  modemStream->println(F("sys reset"));
  String version = readLine(3000);
  if (version == "") {
    debugPrintLn(F("Invalid version"));
    return;
  }

  model = version.substring(0, version.indexOf(' '));
  debugPrint(F("Version is "));
  debugPrint(version);
  debugPrint(F(", model is "));
  debugPrintLn(model);

  String devEui = readValue(F("sys get hweui"));
  String str = "";
  str.concat(F("mac set deveui "));
  str.concat(devEui);
  sendCommand(str);

  String devEui = readValue(F("sys get hweui"));
  String str = "";
  str.concat(F("mac set deveui "));
  str.concat(devEui);
  sendCommand(str);

  str = "";
  str.concat(F("mac set adr "));
  if(adr){
    str.concat(F("on"));
  } else {
    str.concat(F("off"));
  }
  sendCommand(str);
}

void TheThingsNetwork::onMessage(void (*cb)(const byte* payload, int length, int port)) {
  this->messageCallback = cb;
}

bool TheThingsNetwork::personalize(const byte devAddr[4], const byte nwkSKey[16], const byte appSKey[16]) {
  reset();
  sendCommand(F("mac set devaddr"), devAddr, 4);
  sendCommand(F("mac set nwkskey"), nwkSKey, 16);
  sendCommand(F("mac set appskey"), appSKey, 16);
  return personalize();
}

bool TheThingsNetwork::personalize() {
  configureChannels(this->sf, this->fsb);
  sendCommand(F("mac join abp"));
  String response = readLine();
  if (response != F("accepted")) {
    debugPrint(F("Personalize not accepted: "));
    debugPrintLn(response);
    return false;
  }

  debugPrint(F("Personalize accepted. Status: "));
  debugPrintLn(readValue(F("mac get status")));
  return true;
}

bool TheThingsNetwork::provision(const byte appEui[8], const byte appKey[16]) {
  sendCommand(F("mac set appeui"), appEui, 8);
  sendCommand(F("mac set appkey"), appKey, 16);
  return sendCommand(F("mac save"), 50000);
}

bool TheThingsNetwork::join(int retries, long int retryDelay) {
  configureChannels(this->sf, this->fsb);
  String devEui = readValue(F("sys get hweui"));
  String str = "";
  str.concat(F("mac set deveui "));
  str.concat(devEui);
  sendCommand(str);
  while (retries != 0) {
    if (retries > 0) {
      retries--;
    }
    if (!sendCommand(F("mac join otaa"))) {
      debugPrintLn(F("Send join command failed"));
      delay(retryDelay);
      continue;
    }
    String response = readLine(10000);
    if (response != F("accepted")) {
      debugPrint(F("Join not accepted: "));
      debugPrintLn(response);
      delay(retryDelay);
      continue;
    }
    debugPrint(F("Join accepted. Status: "));
    debugPrintLn(readValue(F("mac get status")));
    debugPrint(F("DevAddr: "));
    debugPrintLn(readValue(F("mac get devaddr")));
    return true;
  }
  return false;
}

bool TheThingsNetwork::join(const byte appEui[8], const byte appKey[16], int retries, long int retryDelay) {
  reset();
  provision(appEui, appKey);
  return join(retries, retryDelay);
}

int TheThingsNetwork::sendBytes(const byte* payload, int length, int port, bool confirm) {
  String str = "";
  str.concat(F("mac tx "));
  str.concat(confirm ? F("cnf ") : F("uncnf "));
  str.concat(port);
  if (!sendCommand(str, payload, length)) {
    debugPrintLn(F("Send command failed"));
    return -1;
  }

  String response = readLine(10000);
  if (response == "") {
    debugPrintLn(F("Time-out"));
    return -2;
  }
  if (response == F("mac_tx_ok")) {
    debugPrintLn(F("Successful transmission"));
    return 1;
  }
  if (response.startsWith(F("mac_rx"))) {
    int portEnds = response.indexOf(" ", 7);
    int downlinkPort = response.substring(7, portEnds).toInt();
    String data = response.substring(portEnds + 1);
    int downlinkLength = data.length() / 2;
    byte downlink[64];
    for (int i = 0, d = 0; i < downlinkLength; i++, d += 2)
      downlink[i] = TTN_HEX_PAIR_TO_BYTE(data[d], data[d+1]);
    debugPrint(F("Successful transmission. Received "));
    debugPrint(downlinkLength);
    debugPrintLn(F(" bytes"));
    if (this->messageCallback)
      this->messageCallback(downlink, downlinkLength, downlinkPort);
    return 2;
  }

  debugPrint(F("Unexpected response: "));
  debugPrintLn(response);
  return -10;
}

int TheThingsNetwork::poll(int port, bool confirm) {
  byte payload[] = { 0x00 };
  return sendBytes(payload, 1, port, confirm);
}

void TheThingsNetwork::showStatus() {
  debugPrint(F("EUI: "));
  debugPrintLn(readValue(F("sys get hweui")));
  debugPrint(F("Battery: "));
  debugPrintLn(readValue(F("sys get vdd")));
  debugPrint(F("AppEUI: "));
  debugPrintLn(readValue(F("mac get appeui")));
  debugPrint(F("DevEUI: "));
  debugPrintLn(readValue(F("mac get deveui")));

  if (this->model == F("RN2483")) {
    debugPrint(F("Band: "));
    debugPrintLn(readValue(F("mac get band")));
  }

  debugPrint(F("Data Rate: "));
  debugPrintLn(readValue(F("mac get dr")));
  debugPrint(F("RX Delay 1: "));
  debugPrintLn(readValue(F("mac get rxdelay1")));
  debugPrint(F("RX Delay 2: "));
  debugPrintLn(readValue(F("mac get rxdelay2")));
}

void TheThingsNetwork::configureEU868(int sf) {
  int ch;
  int dr = -1;
  long int freq = 867100000;
  String str = "";

  str.concat(F("mac set rx2 3 869525000"));
  sendCommand(str);
  str = "";
  for (ch = 0; ch <= 7; ch++) {
    if (ch >= 3) {
      str.concat(F("mac set ch freq "));
      str.concat(ch);
      str.concat(F(" "));
      str.concat(freq);
      sendCommand(str);
      str = "";
      str.concat(F("mac set ch drrange "));
      str.concat(ch);
      str.concat(F(" 0 5"));
      sendCommand(str);
      str = "";
      str.concat(F("mac set ch status "));
      str.concat(ch);
      str.concat(F(" on"));
      sendCommand(str);
      str = "";
      freq = freq + 200000;
    }
    str.concat(F("mac set ch dcycle "));
    str.concat(ch);
    str.concat(F(" 799"));
    sendCommand(str);
    str = "";
  }
  str.concat(F("mac set ch drrange 1 0 6"));
  sendCommand(str);
  str = "";
  str.concat(F("mac set pwridx "));
  str.concat(TTN_PWRIDX_868);
  sendCommand(str);
  switch (sf) {
    case 7:
      dr = 5;
      break;
    case 8:
      dr = 4;
      break;
    case 9:
      dr = 3;
      break;
    case 10:
      dr = 2;
      break;
    case 11:
      dr = 1;
      break;
    case 12:
      dr = 0;
      break;
    default:
      debugPrintLn(F("Invalid SF"))
      break;
  }
  if (dr > -1){
    str = "";
    str.concat(F("mac set dr "));
    str.concat(dr);
    sendCommand(str);
  }
}

void TheThingsNetwork::configureUS915(int sf, int fsb) {
  int ch;
  int dr = -1;
  String str = "";
  int chLow = fsb > 0 ? (fsb - 1) * 8 : 0;
  int chHigh = fsb > 0 ? chLow + 7 : 71;
  int ch500 = fsb + 63;

  sendCommand(F("radio set freq 904200000"));
  str = "";
  str.concat(F("mac set pwridx "));
  str.concat(TTN_PWRIDX_915);
  sendCommand(str);
  for (ch = 0; ch < 72; ch++) {
    str = "";
    str.concat(F("mac set ch status "));
    str.concat(ch);
    if (ch == ch500 || ch <= chHigh && ch >= chLow) {
      str.concat(F(" on"));
      sendCommand(str);
      if (ch < 63) {
        str = "";
        str.concat(F("mac set ch drrange "));
        str.concat(ch);
        str.concat(F(" 0 3"));
        sendCommand(str);
        str = "";
      }
    }
    else {
      str.concat(F(" off"));
      sendCommand(str);
    }
  }
  switch (sf) {
    case 7:
      dr = 3;
      break;
    case 8:
     dr = 2;
     break;
    case 9:
      dr = 1;
      break;
    case 10:
      dr = 0;
      break;
    default:
      debugPrintLn(F("Invalid SF"))
      break;
  }
  if (dr > -1){
    str = "";
    str.concat(F("mac set dr "));
    str.concat(dr);
    sendCommand(str);
  }
}

void TheThingsNetwork::configureChannels(int sf, int fsb) {
  switch (this->fp) {
    case TTN_FP_EU868:
      configureEU868(sf);
      break;
    case TTN_FP_US915:
      configureUS915(sf, fsb);
      break;
    default:
      debugPrintLn("Invalid frequency plan");
      break;
  }
}

TheThingsNetwork::TheThingsNetwork(Stream& modemStream, Stream& debugStream, fp_ttn_t fp, int sf, int fsb) {
  this->debugStream = &debugStream;
  this->modemStream = &modemStream;
  this->fp = fp;
  this->sf = sf;
  this->fsb = fsb;
}
<commit_msg>remove dupe code<commit_after>// Copyright © 2016 The Things Network
// Use of this source code is governed by the MIT license that can be found in the LICENSE file.

#include <Arduino.h>
#include <TheThingsNetwork.h>

#define debugPrintLn(...) { if (debugStream) debugStream->println(__VA_ARGS__); }
#define debugPrint(...) { if (debugStream) debugStream->print(__VA_ARGS__); }

String TheThingsNetwork::readLine(int waitTime) {
  unsigned long start = millis();
  while (millis() < start + waitTime) {
    String line = modemStream->readStringUntil('\n');
    if (line.length() > 0) {
      return line.substring(0, line.length() - 1);
    }
  }
  return "";
}

bool TheThingsNetwork::waitForOK(int waitTime, String okMessage) {
  String line = readLine(waitTime);
  if (line == "") {
    debugPrintLn(F("Wait for OK time-out expired"));
    return false;
  }

  if (line != okMessage) {
    debugPrint(F("Response is not OK: "));
    debugPrintLn(line);
    return false;
  }

  return true;
}

String TheThingsNetwork::readValue(String cmd) {
  modemStream->println(cmd);
  return readLine();
}

bool TheThingsNetwork::sendCommand(String cmd, int waitTime) {
  debugPrint(F("Sending: "));
  debugPrintLn(cmd);

  modemStream->println(cmd);

  return waitForOK(waitTime);
}

bool TheThingsNetwork::sendCommand(String cmd, String value, int waitTime) {
  int l = value.length();
  byte buf[l];
  value.getBytes(buf, l);

  return sendCommand(cmd, buf, l, waitTime);
}

char btohexa_high(unsigned char b) {
  b >>= 4;
  return (b > 0x9u) ? b + 'A' - 10 : b + '0';
}

char btohexa_low(unsigned char b) {
  b &= 0x0F;
  return (b > 0x9u) ? b + 'A' - 10 : b + '0';
}

bool TheThingsNetwork::sendCommand(String cmd, const byte *buf, int length, int waitTime) {
  debugPrint(F("Sending: "));
  debugPrint(cmd);
  debugPrint(F(" with "));
  debugPrint(length);
  debugPrintLn(F(" bytes"));

  modemStream->print(cmd + " ");

  for (int i = 0; i < length; i++) {
    modemStream->print(btohexa_high(buf[i]));
    modemStream->print(btohexa_low(buf[i]));
  }
  modemStream->println();

  return waitForOK(waitTime);
}

void TheThingsNetwork::reset(bool adr) {
  #if !TTN_ADR_SUPPORTED
    adr = false;
  #endif

  modemStream->println(F("sys reset"));
  String version = readLine(3000);
  if (version == "") {
    debugPrintLn(F("Invalid version"));
    return;
  }

  model = version.substring(0, version.indexOf(' '));
  debugPrint(F("Version is "));
  debugPrint(version);
  debugPrint(F(", model is "));
  debugPrintLn(model);

  String devEui = readValue(F("sys get hweui"));
  String str = "";
  str.concat(F("mac set deveui "));
  str.concat(devEui);
  sendCommand(str);

  str = "";
  str.concat(F("mac set adr "));
  if(adr){
    str.concat(F("on"));
  } else {
    str.concat(F("off"));
  }
  sendCommand(str);
}

void TheThingsNetwork::onMessage(void (*cb)(const byte* payload, int length, int port)) {
  this->messageCallback = cb;
}

bool TheThingsNetwork::personalize(const byte devAddr[4], const byte nwkSKey[16], const byte appSKey[16]) {
  reset();
  sendCommand(F("mac set devaddr"), devAddr, 4);
  sendCommand(F("mac set nwkskey"), nwkSKey, 16);
  sendCommand(F("mac set appskey"), appSKey, 16);
  return personalize();
}

bool TheThingsNetwork::personalize() {
  configureChannels(this->sf, this->fsb);
  sendCommand(F("mac join abp"));
  String response = readLine();
  if (response != F("accepted")) {
    debugPrint(F("Personalize not accepted: "));
    debugPrintLn(response);
    return false;
  }

  debugPrint(F("Personalize accepted. Status: "));
  debugPrintLn(readValue(F("mac get status")));
  return true;
}

bool TheThingsNetwork::provision(const byte appEui[8], const byte appKey[16]) {
  sendCommand(F("mac set appeui"), appEui, 8);
  sendCommand(F("mac set appkey"), appKey, 16);
  return sendCommand(F("mac save"), 50000);
}

bool TheThingsNetwork::join(int retries, long int retryDelay) {
  configureChannels(this->sf, this->fsb);
  String devEui = readValue(F("sys get hweui"));
  String str = "";
  str.concat(F("mac set deveui "));
  str.concat(devEui);
  sendCommand(str);
  while (retries != 0) {
    if (retries > 0) {
      retries--;
    }
    if (!sendCommand(F("mac join otaa"))) {
      debugPrintLn(F("Send join command failed"));
      delay(retryDelay);
      continue;
    }
    String response = readLine(10000);
    if (response != F("accepted")) {
      debugPrint(F("Join not accepted: "));
      debugPrintLn(response);
      delay(retryDelay);
      continue;
    }
    debugPrint(F("Join accepted. Status: "));
    debugPrintLn(readValue(F("mac get status")));
    debugPrint(F("DevAddr: "));
    debugPrintLn(readValue(F("mac get devaddr")));
    return true;
  }
  return false;
}

bool TheThingsNetwork::join(const byte appEui[8], const byte appKey[16], int retries, long int retryDelay) {
  reset();
  provision(appEui, appKey);
  return join(retries, retryDelay);
}

int TheThingsNetwork::sendBytes(const byte* payload, int length, int port, bool confirm) {
  String str = "";
  str.concat(F("mac tx "));
  str.concat(confirm ? F("cnf ") : F("uncnf "));
  str.concat(port);
  if (!sendCommand(str, payload, length)) {
    debugPrintLn(F("Send command failed"));
    return -1;
  }

  String response = readLine(10000);
  if (response == "") {
    debugPrintLn(F("Time-out"));
    return -2;
  }
  if (response == F("mac_tx_ok")) {
    debugPrintLn(F("Successful transmission"));
    return 1;
  }
  if (response.startsWith(F("mac_rx"))) {
    int portEnds = response.indexOf(" ", 7);
    int downlinkPort = response.substring(7, portEnds).toInt();
    String data = response.substring(portEnds + 1);
    int downlinkLength = data.length() / 2;
    byte downlink[64];
    for (int i = 0, d = 0; i < downlinkLength; i++, d += 2)
      downlink[i] = TTN_HEX_PAIR_TO_BYTE(data[d], data[d+1]);
    debugPrint(F("Successful transmission. Received "));
    debugPrint(downlinkLength);
    debugPrintLn(F(" bytes"));
    if (this->messageCallback)
      this->messageCallback(downlink, downlinkLength, downlinkPort);
    return 2;
  }

  debugPrint(F("Unexpected response: "));
  debugPrintLn(response);
  return -10;
}

int TheThingsNetwork::poll(int port, bool confirm) {
  byte payload[] = { 0x00 };
  return sendBytes(payload, 1, port, confirm);
}

void TheThingsNetwork::showStatus() {
  debugPrint(F("EUI: "));
  debugPrintLn(readValue(F("sys get hweui")));
  debugPrint(F("Battery: "));
  debugPrintLn(readValue(F("sys get vdd")));
  debugPrint(F("AppEUI: "));
  debugPrintLn(readValue(F("mac get appeui")));
  debugPrint(F("DevEUI: "));
  debugPrintLn(readValue(F("mac get deveui")));

  if (this->model == F("RN2483")) {
    debugPrint(F("Band: "));
    debugPrintLn(readValue(F("mac get band")));
  }

  debugPrint(F("Data Rate: "));
  debugPrintLn(readValue(F("mac get dr")));
  debugPrint(F("RX Delay 1: "));
  debugPrintLn(readValue(F("mac get rxdelay1")));
  debugPrint(F("RX Delay 2: "));
  debugPrintLn(readValue(F("mac get rxdelay2")));
}

void TheThingsNetwork::configureEU868(int sf) {
  int ch;
  int dr = -1;
  long int freq = 867100000;
  String str = "";

  str.concat(F("mac set rx2 3 869525000"));
  sendCommand(str);
  str = "";
  for (ch = 0; ch <= 7; ch++) {
    if (ch >= 3) {
      str.concat(F("mac set ch freq "));
      str.concat(ch);
      str.concat(F(" "));
      str.concat(freq);
      sendCommand(str);
      str = "";
      str.concat(F("mac set ch drrange "));
      str.concat(ch);
      str.concat(F(" 0 5"));
      sendCommand(str);
      str = "";
      str.concat(F("mac set ch status "));
      str.concat(ch);
      str.concat(F(" on"));
      sendCommand(str);
      str = "";
      freq = freq + 200000;
    }
    str.concat(F("mac set ch dcycle "));
    str.concat(ch);
    str.concat(F(" 799"));
    sendCommand(str);
    str = "";
  }
  str.concat(F("mac set ch drrange 1 0 6"));
  sendCommand(str);
  str = "";
  str.concat(F("mac set pwridx "));
  str.concat(TTN_PWRIDX_868);
  sendCommand(str);
  switch (sf) {
    case 7:
      dr = 5;
      break;
    case 8:
      dr = 4;
      break;
    case 9:
      dr = 3;
      break;
    case 10:
      dr = 2;
      break;
    case 11:
      dr = 1;
      break;
    case 12:
      dr = 0;
      break;
    default:
      debugPrintLn(F("Invalid SF"))
      break;
  }
  if (dr > -1){
    str = "";
    str.concat(F("mac set dr "));
    str.concat(dr);
    sendCommand(str);
  }
}

void TheThingsNetwork::configureUS915(int sf, int fsb) {
  int ch;
  int dr = -1;
  String str = "";
  int chLow = fsb > 0 ? (fsb - 1) * 8 : 0;
  int chHigh = fsb > 0 ? chLow + 7 : 71;
  int ch500 = fsb + 63;

  sendCommand(F("radio set freq 904200000"));
  str = "";
  str.concat(F("mac set pwridx "));
  str.concat(TTN_PWRIDX_915);
  sendCommand(str);
  for (ch = 0; ch < 72; ch++) {
    str = "";
    str.concat(F("mac set ch status "));
    str.concat(ch);
    if (ch == ch500 || ch <= chHigh && ch >= chLow) {
      str.concat(F(" on"));
      sendCommand(str);
      if (ch < 63) {
        str = "";
        str.concat(F("mac set ch drrange "));
        str.concat(ch);
        str.concat(F(" 0 3"));
        sendCommand(str);
        str = "";
      }
    }
    else {
      str.concat(F(" off"));
      sendCommand(str);
    }
  }
  switch (sf) {
    case 7:
      dr = 3;
      break;
    case 8:
     dr = 2;
     break;
    case 9:
      dr = 1;
      break;
    case 10:
      dr = 0;
      break;
    default:
      debugPrintLn(F("Invalid SF"))
      break;
  }
  if (dr > -1){
    str = "";
    str.concat(F("mac set dr "));
    str.concat(dr);
    sendCommand(str);
  }
}

void TheThingsNetwork::configureChannels(int sf, int fsb) {
  switch (this->fp) {
    case TTN_FP_EU868:
      configureEU868(sf);
      break;
    case TTN_FP_US915:
      configureUS915(sf, fsb);
      break;
    default:
      debugPrintLn("Invalid frequency plan");
      break;
  }
}

TheThingsNetwork::TheThingsNetwork(Stream& modemStream, Stream& debugStream, fp_ttn_t fp, int sf, int fsb) {
  this->debugStream = &debugStream;
  this->modemStream = &modemStream;
  this->fp = fp;
  this->sf = sf;
  this->fsb = fsb;
}
<|endoftext|>


<commit_before>/*
 * Copyright(c) Sophist Solutions, Inc. 1990-2014.  All rights reserved
 */
#include    "../StroikaPreComp.h"

#if     qHas_Syslog
#include    <syslog.h>
#endif

#include    "../Characters/CString/Utilities.h"
#include    "../Characters/Format.h"
#include    "../Debug/Trace.h"
#include    "BlockingQueue.h"
#include    "Process.h"
#include    "Thread.h"
#include    "TimeOutException.h"

#include    "Logger.h"

using   namespace   Stroika::Foundation;
using   namespace   Stroika::Foundation::Execution;

using   Memory::Optional;
using   Time::DurationSecondsType;

/*
 ********************************************************************************
 ******************************** Execution::Logger *****************************
 ********************************************************************************
 */
Logger  Logger::sThe_;

namespace {
    BlockingQueue<pair<Logger::Priority, String>>   sOutMsgQ_;
    Execution::Thread                               sBookkeepingThread_;
    bool                                            sOutQMaybeNeedsFlush_ = true;       // sligt optimziation of not using buffering

    // @TODO - not threadsafe - til we add a threadsafe Optional to Stroika - but SB OK
    Optional<DurationSecondsType>                   sSupressDuplicatesThreshold_;

    struct LastMsg_ {
        mutex                               fMutex_;     // mutex so we can update related variables together
        pair<Logger::Priority, String>      fLastMsgSent_;
        Time::DurationSecondsType           fLastSentAt = 0.0;
        unsigned int                        fRepeatCount_ = 0;
    };
    LastMsg_    sLastMsg_;
}

Logger::Logger ()
    : fAppender_ ()
    , fMinLogLevel_ (Priority::eInfo)
    , fBufferingEnabled_ (false)
{
}

void    Logger::SetAppender (const shared_ptr<IAppenderRep>& rep)
{
    fAppender_ = rep;
}

void    Logger::Log_ (Priority logLevel, const String& format, va_list argList)
{
    shared_ptr<IAppenderRep> tmp =   sThe_.fAppender_;   // avoid races and critical sections
    if (tmp.get () != nullptr) {
        auto p = pair<Logger::Priority, String> (logLevel, Characters::FormatV (format.c_str (), argList));
        if (sSupressDuplicatesThreshold_.IsPresent ()) {
            lock_guard<mutex>   critSec (sLastMsg_.fMutex_);
            if (p == sLastMsg_.fLastMsgSent_) {
                sLastMsg_.fRepeatCount_++;
                return; // so will be handled later
            }
            else {
                if (sLastMsg_.fRepeatCount_ > 0) {
                    FlushDupsWarning_ ();
                }
                sLastMsg_.fLastMsgSent_ = p;
                sLastMsg_.fRepeatCount_ = 0;
            }
            sLastMsg_.fLastSentAt = Time::GetTickCount ();
        }
        if (GetBufferingEnabled ()) {
            sOutQMaybeNeedsFlush_ = true;
            sOutMsgQ_.AddTail (p);
        }
        else {
            if (sOutQMaybeNeedsFlush_) {
                FlushBuffer (); // in case recently disabled
            }
            tmp->Log (p.first, p.second);
        }
    }
}

void        Logger::SetBufferingEnabled (bool logBufferingEnabled)
{
    sThe_.fBufferingEnabled_ = logBufferingEnabled;
    UpdateBookkeepingThread_ ();
}

void        Logger::FlushBuffer ()
{
    shared_ptr<IAppenderRep> tmp =   sThe_.fAppender_;   // avoid races and critical sections
    if (tmp != nullptr) {
        while (true) {
            auto p = sOutMsgQ_.RemoveHeadIfPossible ();
            if (p.IsPresent ()) {
                tmp->Log (p->first, p->second);
            }
            else {
                return; // no more entries
            }
        }
    }
    sOutQMaybeNeedsFlush_ = false;
}

Memory::Optional<Time::DurationSecondsType> Logger::GetSuppressDuplicates ()
{
    return sSupressDuplicatesThreshold_;
}

void    Logger::SetSuppressDuplicates (const Optional<DurationSecondsType>& suppressDuplicatesThreshold)
{
    Require (suppressDuplicatesThreshold.IsMissing () or * suppressDuplicatesThreshold > 0.0);
    if (sSupressDuplicatesThreshold_ != suppressDuplicatesThreshold) {
        sSupressDuplicatesThreshold_ = suppressDuplicatesThreshold;
        UpdateBookkeepingThread_ ();
    }
}

void    Logger::FlushDupsWarning_ ()
{
    if (sLastMsg_.fRepeatCount_ > 0) {
        shared_ptr<IAppenderRep> tmp =   sThe_.fAppender_;   // avoid races and critical sections
        if (tmp != nullptr) {
            if (sLastMsg_.fRepeatCount_ == 1) {
                tmp->Log (sLastMsg_.fLastMsgSent_.first, sLastMsg_.fLastMsgSent_.second);
            }
            else {
                tmp->Log (sLastMsg_.fLastMsgSent_.first,  Characters::Format (L"[%d duplicates supressed]: %s", sLastMsg_.fRepeatCount_ - 1, sLastMsg_.fLastMsgSent_.second.c_str ()));
            }
        }
        sLastMsg_.fRepeatCount_ = 0;
        sLastMsg_.fLastMsgSent_.second.clear ();
    }
}

void    Logger::UpdateBookkeepingThread_ ()
{
    sBookkeepingThread_.AbortAndWaitForDone ();
    sBookkeepingThread_ = Thread ();  // so null

    Time::DurationSecondsType   suppressDuplicatesThreshold =   sSupressDuplicatesThreshold_.Value (0);
    bool                        suppressDuplicates          =   suppressDuplicatesThreshold > 0;
    if (suppressDuplicates or GetBufferingEnabled ()) {
        if (suppressDuplicates) {
            sBookkeepingThread_ = Thread ([suppressDuplicatesThreshold] () {
                while (true) {
                    DurationSecondsType time2Wait = max (static_cast<DurationSecondsType> (2), suppressDuplicatesThreshold);    // never wait less than this
                    try {
                        auto p = sOutMsgQ_.RemoveHead (time2Wait);
                        shared_ptr<IAppenderRep> tmp =   sThe_.fAppender_;   // avoid races and critical sections
                        if (tmp != nullptr) {
                            tmp->Log (p.first, p.second);
                        }
                    }
                    catch (const TimeOutException&) {
                    }
                    {
                        lock_guard<mutex>   critSec (sLastMsg_.fMutex_);
                        if (sLastMsg_.fRepeatCount_ > 0 and sLastMsg_.fLastSentAt + suppressDuplicatesThreshold < Time::GetTickCount ()) {
                            FlushDupsWarning_ ();
                        }
                    }
                }
            });
        }
        else {
            sBookkeepingThread_ = Thread ([] () {
                while (true) {
                    auto p = sOutMsgQ_.RemoveHead ();
                    shared_ptr<IAppenderRep> tmp =   sThe_.fAppender_;   // avoid races and critical sections
                    if (tmp != nullptr) {
                        tmp->Log (p.first, p.second);
                    }
                }
            });
        }
        sBookkeepingThread_.SetThreadName (L"Logger Bookkeeping");
        sBookkeepingThread_.SetThreadPriority (Thread::Priority::eBelowNormal);
        sBookkeepingThread_.Start ();
    }

    // manually push out pending messages
    FlushBuffer ();
}

/*
 ********************************************************************************
 ************************** Execution::IAppenderRep *****************************
 ********************************************************************************
 */
Logger::IAppenderRep::~IAppenderRep ()
{
}

#if     qHas_Syslog
/*
 ********************************************************************************
 ************************ Execution::SysLogAppender *****************************
 ********************************************************************************
 */
namespace   {
    string mkMsg_ (const String& applicationName)
    {
        return Characters::CString::Format ("%s[%d]", applicationName.AsNarrowSDKString ().c_str (), GetCurrentProcessID ());
    }
}
Logger::SysLogAppender::SysLogAppender (const String& applicationName)
    : fApplicationName_ (mkMsg_ (applicationName))
{
    openlog (fApplicationName_.c_str (), 0, LOG_DAEMON);    // not sure what facility to pass?
}

Logger::SysLogAppender::SysLogAppender (const String& applicationName, int facility)
    : fApplicationName_ (mkMsg_ (applicationName))
{
    openlog (fApplicationName_.c_str (), 0, facility);
}

Logger::SysLogAppender::~SysLogAppender ()
{
    closelog ();
}

void    Logger::SysLogAppender::Log (Priority logLevel, const String& message)
{
    DbgTrace (L"SYSLOG: %d: %s", logLevel, message.c_str ());
    int sysLogLevel = LOG_NOTICE;   // doesnt matter cuz assert error if hit
    switch (logLevel) {
        case Priority::eDebug:
            sysLogLevel = LOG_DEBUG;
            break;
        case Priority::eInfo:
            sysLogLevel = LOG_INFO;
            break;
        case Priority::eNotice:
            sysLogLevel = LOG_NOTICE;
            break;
        case Priority::eWarning:
            sysLogLevel = LOG_WARNING;
            break;
        case Priority::eError:
            sysLogLevel = LOG_DEBUG;
            break;
        case Priority::eCriticalError:
            sysLogLevel = LOG_CRIT;
            break;
        case Priority::eAlertError:
            sysLogLevel = LOG_ALERT;
            break;
        case Priority::eEmergency:
            sysLogLevel = LOG_EMERG;
            break;
        default:
            RequireNotReached ();
    }
    syslog (sysLogLevel, "%s", message.AsNarrowSDKString ().c_str ());
}
#endif

/*
 ********************************************************************************
 ************************** Execution::FileAppender *****************************
 ********************************************************************************
 */
Logger::FileAppender::FileAppender (const String& fileName)
{
    AssertNotImplemented ();
}

void    Logger::FileAppender::Log (Priority logLevel, const String& message)
{
    AssertNotImplemented ();
}

#if     qPlatform_Windows
/*
 ********************************************************************************
 ************************ Execution::SysLogAppender *****************************
 ********************************************************************************
 */
Logger::WindowsEventLogAppender::WindowsEventLogAppender ()
{
}

void    Logger::WindowsEventLogAppender::Log (Priority logLevel, const String& message)
{
    /*
     * VERY QUICK HACK - AT LEAST DUMPS SOME INFO TO EVENTLOG - BUT MUCH TWEAKING LEFT TODO
     */
    const   TCHAR   kEventSourceName[]  =   _T ("xxxtest");
    WORD    eventType   =   EVENTLOG_ERROR_TYPE;
    switch (logLevel) {
        case Priority::eDebug:
            eventType = EVENTLOG_INFORMATION_TYPE;
            break;
        case Priority::eInfo:
            eventType = EVENTLOG_INFORMATION_TYPE;
            break;
        case Priority::eNotice:
            eventType = EVENTLOG_INFORMATION_TYPE;
            break;
        case Priority::eWarning:
            eventType = EVENTLOG_WARNING_TYPE;
            break;
        case Priority::eError:
            eventType = EVENTLOG_ERROR_TYPE;
            break;
        case Priority::eAlertError:
            eventType = EVENTLOG_ERROR_TYPE;
            break;
        case Priority::eEmergency:
            eventType = EVENTLOG_ERROR_TYPE;
            break;
    }
#define CATEGORY_Normal                  0x00000001L
    WORD    eventCategoryID =   CATEGORY_Normal;
    // See SPR#565 for wierdness - where I cannot really get these paid attention to
    // by the Windows EventLog. So had to use the .Net eventlogger. It SEEMS
#define EVENT_Message                    0x00000064L
    const   DWORD   kEventID            =   EVENT_Message;
    HANDLE  hEventSource = RegisterEventSource (NULL, kEventSourceName);
    Verify (hEventSource != NULL);
    SDKString tmp = message.AsSDKString ();
    const Characters::SDKChar* msg = tmp.c_str ();
    Verify (::ReportEvent (
                hEventSource,
                eventType,
                eventCategoryID,
                kEventID,
                NULL,
                (WORD)1,
                0,
                &msg,
                NULL
            )
           );
    Verify (::DeregisterEventSource (hEventSource));
}
#endif<commit_msg>use new Containers::Optional<> in logger code<commit_after>/*
 * Copyright(c) Sophist Solutions, Inc. 1990-2014.  All rights reserved
 */
#include    "../StroikaPreComp.h"

#if     qHas_Syslog
#include    <syslog.h>
#endif

#include    "../Characters/CString/Utilities.h"
#include    "../Characters/Format.h"
#include    "../Containers/Optional.h"
#include    "../Debug/Trace.h"
#include    "BlockingQueue.h"
#include    "Process.h"
#include    "Thread.h"
#include    "TimeOutException.h"

#include    "Logger.h"

using   namespace   Stroika::Foundation;
using   namespace   Stroika::Foundation::Execution;

using   Time::DurationSecondsType;

/*
 ********************************************************************************
 ******************************** Execution::Logger *****************************
 ********************************************************************************
 */
Logger  Logger::sThe_;

namespace {
    BlockingQueue<pair<Logger::Priority, String>>   sOutMsgQ_;
    Execution::Thread                               sBookkeepingThread_;
    bool                                            sOutQMaybeNeedsFlush_ = true;       // sligt optimziation of not using buffering

    Containers::Optional<DurationSecondsType>       sSupressDuplicatesThreshold_;

    struct LastMsg_ {
        mutex                               fMutex_;     // mutex so we can update related variables together
        pair<Logger::Priority, String>      fLastMsgSent_;
        Time::DurationSecondsType           fLastSentAt = 0.0;
        unsigned int                        fRepeatCount_ = 0;
    };
    LastMsg_    sLastMsg_;
}

Logger::Logger ()
    : fAppender_ ()
    , fMinLogLevel_ (Priority::eInfo)
    , fBufferingEnabled_ (false)
{
}

void    Logger::SetAppender (const shared_ptr<IAppenderRep>& rep)
{
    fAppender_ = rep;
}

void    Logger::Log_ (Priority logLevel, const String& format, va_list argList)
{
    shared_ptr<IAppenderRep> tmp =   sThe_.fAppender_;   // avoid races and critical sections
    if (tmp.get () != nullptr) {
        auto p = pair<Logger::Priority, String> (logLevel, Characters::FormatV (format.c_str (), argList));
        if (sSupressDuplicatesThreshold_.IsPresent ()) {
            lock_guard<mutex>   critSec (sLastMsg_.fMutex_);
            if (p == sLastMsg_.fLastMsgSent_) {
                sLastMsg_.fRepeatCount_++;
                return; // so will be handled later
            }
            else {
                if (sLastMsg_.fRepeatCount_ > 0) {
                    FlushDupsWarning_ ();
                }
                sLastMsg_.fLastMsgSent_ = p;
                sLastMsg_.fRepeatCount_ = 0;
            }
            sLastMsg_.fLastSentAt = Time::GetTickCount ();
        }
        if (GetBufferingEnabled ()) {
            sOutQMaybeNeedsFlush_ = true;
            sOutMsgQ_.AddTail (p);
        }
        else {
            if (sOutQMaybeNeedsFlush_) {
                FlushBuffer (); // in case recently disabled
            }
            tmp->Log (p.first, p.second);
        }
    }
}

void        Logger::SetBufferingEnabled (bool logBufferingEnabled)
{
    sThe_.fBufferingEnabled_ = logBufferingEnabled;
    UpdateBookkeepingThread_ ();
}

void        Logger::FlushBuffer ()
{
    shared_ptr<IAppenderRep> tmp =   sThe_.fAppender_;   // avoid races and critical sections
    if (tmp != nullptr) {
        while (true) {
            auto p = sOutMsgQ_.RemoveHeadIfPossible ();
            if (p.IsPresent ()) {
                tmp->Log (p->first, p->second);
            }
            else {
                return; // no more entries
            }
        }
    }
    sOutQMaybeNeedsFlush_ = false;
}

Memory::Optional<Time::DurationSecondsType> Logger::GetSuppressDuplicates ()
{
    return Memory::Optional<Time::DurationSecondsType> (sSupressDuplicatesThreshold_);
}

void    Logger::SetSuppressDuplicates (const Memory::Optional<DurationSecondsType>& suppressDuplicatesThreshold)
{
    Require (suppressDuplicatesThreshold.IsMissing () or * suppressDuplicatesThreshold > 0.0);
    if (sSupressDuplicatesThreshold_ != suppressDuplicatesThreshold) {
        sSupressDuplicatesThreshold_ = suppressDuplicatesThreshold;
        UpdateBookkeepingThread_ ();
    }
}

void    Logger::FlushDupsWarning_ ()
{
    if (sLastMsg_.fRepeatCount_ > 0) {
        shared_ptr<IAppenderRep> tmp =   sThe_.fAppender_;   // avoid races and critical sections
        if (tmp != nullptr) {
            if (sLastMsg_.fRepeatCount_ == 1) {
                tmp->Log (sLastMsg_.fLastMsgSent_.first, sLastMsg_.fLastMsgSent_.second);
            }
            else {
                tmp->Log (sLastMsg_.fLastMsgSent_.first,  Characters::Format (L"[%d duplicates supressed]: %s", sLastMsg_.fRepeatCount_ - 1, sLastMsg_.fLastMsgSent_.second.c_str ()));
            }
        }
        sLastMsg_.fRepeatCount_ = 0;
        sLastMsg_.fLastMsgSent_.second.clear ();
    }
}

void    Logger::UpdateBookkeepingThread_ ()
{
    sBookkeepingThread_.AbortAndWaitForDone ();
    sBookkeepingThread_ = Thread ();  // so null

    Time::DurationSecondsType   suppressDuplicatesThreshold =   sSupressDuplicatesThreshold_.Value (0);
    bool                        suppressDuplicates          =   suppressDuplicatesThreshold > 0;
    if (suppressDuplicates or GetBufferingEnabled ()) {
        if (suppressDuplicates) {
            sBookkeepingThread_ = Thread ([suppressDuplicatesThreshold] () {
                while (true) {
                    DurationSecondsType time2Wait = max (static_cast<DurationSecondsType> (2), suppressDuplicatesThreshold);    // never wait less than this
                    try {
                        auto p = sOutMsgQ_.RemoveHead (time2Wait);
                        shared_ptr<IAppenderRep> tmp =   sThe_.fAppender_;   // avoid races and critical sections
                        if (tmp != nullptr) {
                            tmp->Log (p.first, p.second);
                        }
                    }
                    catch (const TimeOutException&) {
                    }
                    {
                        lock_guard<mutex>   critSec (sLastMsg_.fMutex_);
                        if (sLastMsg_.fRepeatCount_ > 0 and sLastMsg_.fLastSentAt + suppressDuplicatesThreshold < Time::GetTickCount ()) {
                            FlushDupsWarning_ ();
                        }
                    }
                }
            });
        }
        else {
            sBookkeepingThread_ = Thread ([] () {
                while (true) {
                    auto p = sOutMsgQ_.RemoveHead ();
                    shared_ptr<IAppenderRep> tmp =   sThe_.fAppender_;   // avoid races and critical sections
                    if (tmp != nullptr) {
                        tmp->Log (p.first, p.second);
                    }
                }
            });
        }
        sBookkeepingThread_.SetThreadName (L"Logger Bookkeeping");
        sBookkeepingThread_.SetThreadPriority (Thread::Priority::eBelowNormal);
        sBookkeepingThread_.Start ();
    }

    // manually push out pending messages
    FlushBuffer ();
}

/*
 ********************************************************************************
 ************************** Execution::IAppenderRep *****************************
 ********************************************************************************
 */
Logger::IAppenderRep::~IAppenderRep ()
{
}

#if     qHas_Syslog
/*
 ********************************************************************************
 ************************ Execution::SysLogAppender *****************************
 ********************************************************************************
 */
namespace   {
    string mkMsg_ (const String& applicationName)
    {
        return Characters::CString::Format ("%s[%d]", applicationName.AsNarrowSDKString ().c_str (), GetCurrentProcessID ());
    }
}
Logger::SysLogAppender::SysLogAppender (const String& applicationName)
    : fApplicationName_ (mkMsg_ (applicationName))
{
    openlog (fApplicationName_.c_str (), 0, LOG_DAEMON);    // not sure what facility to pass?
}

Logger::SysLogAppender::SysLogAppender (const String& applicationName, int facility)
    : fApplicationName_ (mkMsg_ (applicationName))
{
    openlog (fApplicationName_.c_str (), 0, facility);
}

Logger::SysLogAppender::~SysLogAppender ()
{
    closelog ();
}

void    Logger::SysLogAppender::Log (Priority logLevel, const String& message)
{
    DbgTrace (L"SYSLOG: %d: %s", logLevel, message.c_str ());
    int sysLogLevel = LOG_NOTICE;   // doesnt matter cuz assert error if hit
    switch (logLevel) {
        case Priority::eDebug:
            sysLogLevel = LOG_DEBUG;
            break;
        case Priority::eInfo:
            sysLogLevel = LOG_INFO;
            break;
        case Priority::eNotice:
            sysLogLevel = LOG_NOTICE;
            break;
        case Priority::eWarning:
            sysLogLevel = LOG_WARNING;
            break;
        case Priority::eError:
            sysLogLevel = LOG_DEBUG;
            break;
        case Priority::eCriticalError:
            sysLogLevel = LOG_CRIT;
            break;
        case Priority::eAlertError:
            sysLogLevel = LOG_ALERT;
            break;
        case Priority::eEmergency:
            sysLogLevel = LOG_EMERG;
            break;
        default:
            RequireNotReached ();
    }
    syslog (sysLogLevel, "%s", message.AsNarrowSDKString ().c_str ());
}
#endif

/*
 ********************************************************************************
 ************************** Execution::FileAppender *****************************
 ********************************************************************************
 */
Logger::FileAppender::FileAppender (const String& fileName)
{
    AssertNotImplemented ();
}

void    Logger::FileAppender::Log (Priority logLevel, const String& message)
{
    AssertNotImplemented ();
}

#if     qPlatform_Windows
/*
 ********************************************************************************
 ************************ Execution::SysLogAppender *****************************
 ********************************************************************************
 */
Logger::WindowsEventLogAppender::WindowsEventLogAppender ()
{
}

void    Logger::WindowsEventLogAppender::Log (Priority logLevel, const String& message)
{
    /*
     * VERY QUICK HACK - AT LEAST DUMPS SOME INFO TO EVENTLOG - BUT MUCH TWEAKING LEFT TODO
     */
    const   TCHAR   kEventSourceName[]  =   _T ("xxxtest");
    WORD    eventType   =   EVENTLOG_ERROR_TYPE;
    switch (logLevel) {
        case Priority::eDebug:
            eventType = EVENTLOG_INFORMATION_TYPE;
            break;
        case Priority::eInfo:
            eventType = EVENTLOG_INFORMATION_TYPE;
            break;
        case Priority::eNotice:
            eventType = EVENTLOG_INFORMATION_TYPE;
            break;
        case Priority::eWarning:
            eventType = EVENTLOG_WARNING_TYPE;
            break;
        case Priority::eError:
            eventType = EVENTLOG_ERROR_TYPE;
            break;
        case Priority::eAlertError:
            eventType = EVENTLOG_ERROR_TYPE;
            break;
        case Priority::eEmergency:
            eventType = EVENTLOG_ERROR_TYPE;
            break;
    }
#define CATEGORY_Normal                  0x00000001L
    WORD    eventCategoryID =   CATEGORY_Normal;
    // See SPR#565 for wierdness - where I cannot really get these paid attention to
    // by the Windows EventLog. So had to use the .Net eventlogger. It SEEMS
#define EVENT_Message                    0x00000064L
    const   DWORD   kEventID            =   EVENT_Message;
    HANDLE  hEventSource = RegisterEventSource (NULL, kEventSourceName);
    Verify (hEventSource != NULL);
    SDKString tmp = message.AsSDKString ();
    const Characters::SDKChar* msg = tmp.c_str ();
    Verify (::ReportEvent (
                hEventSource,
                eventType,
                eventCategoryID,
                kEventID,
                NULL,
                (WORD)1,
                0,
                &msg,
                NULL
            )
           );
    Verify (::DeregisterEventSource (hEventSource));
}
#endif<|endoftext|>


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

  Library:   CTK

  Copyright (c) Kitware Inc.

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

  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.

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

// Qt includes
#include <QApplication>
#include <QDir>
#include <QTimer>

// ctk includes
#include "ctkUtils.h"

// ctkDICOMCore includes
#include "ctkDICOMDatabase.h"

// ctkDICOMWidget includes
#include "ctkDICOMBrowser.h"

// STD includes
#include <iostream>

int ctkDICOMBrowserTest1( int argc, char * argv [] )
{
  QApplication app(argc, argv);

  qDebug() << "argc = " << argc;
  for (int i = 0; i < argc; ++i)
    {
    qDebug() << "\t" << argv[i];
    }

  QFileInfo tempFileInfo(QDir::tempPath() + QString("/ctkDICOMBrowserTest1-db"));
  QString dbDir = tempFileInfo.absoluteFilePath();
  qDebug() << "\n\nUsing directory: " << dbDir;
  if (tempFileInfo.exists())
    {
    qDebug() << "\n\nRemoving directory: " << dbDir;
    ctk::removeDirRecursively(dbDir);
    }
  qDebug() << "\n\nMaking directory: " << dbDir;
  QDir dir(dbDir);
  dir.mkdir(dbDir);

  ctkDICOMBrowser browser;
  browser.setDatabaseDirectory(dbDir);

  browser.show();

  browser.setDisplayImportSummary(false);
  qDebug() << "Importing directory " << argv[1];

  // make sure copy/link dialog doesn't pop up, always copy on import
  QSettings settings;
  QString settingsString = settings.value("MainWindow/DontConfirmCopyOnImport").toString();
  settings.setValue("MainWindow/DontConfirmCopyOnImport", QString("0"));

  browser.onImportDirectory(argv[1]);

  // reset to the original copy/import setting
  settings.setValue("MainWindow/DontConfirmCopyOnImport", settingsString);

  if (browser.patientsAddedDuringImport() != 1
    || browser.studiesAddedDuringImport() != 1
    || browser.seriesAddedDuringImport() != 1
    || browser.instancesAddedDuringImport() != 100)
    {
    qDebug() << "\n\nDirectory did not import as expected!\n\n";
    return EXIT_FAILURE;
    }

  qDebug() << "\n\nAdded to database directory: " << dbDir;

  if (argc <= 2 || QString(argv[argc - 1]) != "-I")
    {
    QTimer::singleShot(200, &app, SLOT(quit()));
    }

  return app.exec();
}
<commit_msg>STYLE: Refactor ctkDICOMBrowserTest1 to use testing macros<commit_after>/*=========================================================================

  Library:   CTK

  Copyright (c) Kitware Inc.

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

  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.

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

// Qt includes
#include <QApplication>
#include <QDir>
#include <QTimer>

// ctk includes
#include "ctkCoreTestingMacros.h"
#include "ctkUtils.h"

// ctkDICOMCore includes
#include "ctkDICOMDatabase.h"

// ctkDICOMWidget includes
#include "ctkDICOMBrowser.h"

// STD includes
#include <iostream>

int ctkDICOMBrowserTest1( int argc, char * argv [] )
{
  QApplication app(argc, argv);

  qDebug() << "argc = " << argc;
  for (int i = 0; i < argc; ++i)
    {
    qDebug() << "\t" << argv[i];
    }

  QFileInfo tempFileInfo(QDir::tempPath() + QString("/ctkDICOMBrowserTest1-db"));
  QString dbDir = tempFileInfo.absoluteFilePath();
  qDebug() << "\n\nUsing directory: " << dbDir;
  if (tempFileInfo.exists())
    {
    qDebug() << "\n\nRemoving directory: " << dbDir;
    ctk::removeDirRecursively(dbDir);
    }
  qDebug() << "\n\nMaking directory: " << dbDir;
  QDir dir(dbDir);
  dir.mkdir(dbDir);

  ctkDICOMBrowser browser;
  browser.setDatabaseDirectory(dbDir);

  browser.show();

  browser.setDisplayImportSummary(false);
  qDebug() << "Importing directory " << argv[1];

  // make sure copy/link dialog doesn't pop up, always copy on import
  QSettings settings;
  QString settingsString = settings.value("MainWindow/DontConfirmCopyOnImport").toString();
  settings.setValue("MainWindow/DontConfirmCopyOnImport", QString("0"));

  browser.onImportDirectory(argv[1]);

  // reset to the original copy/import setting
  settings.setValue("MainWindow/DontConfirmCopyOnImport", settingsString);

  CHECK_INT(browser.patientsAddedDuringImport(), 1);
  CHECK_INT(browser.studiesAddedDuringImport(), 1);
  CHECK_INT(browser.seriesAddedDuringImport(), 1);
  CHECK_INT(browser.instancesAddedDuringImport(), 100);

  qDebug() << "\n\nAdded to database directory: " << dbDir;

  if (argc <= 2 || QString(argv[argc - 1]) != "-I")
    {
    QTimer::singleShot(200, &app, SLOT(quit()));
    }

  return app.exec();
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: hfi_typedef.cxx,v $
 *
 *  $Revision: 1.5 $
 *
 *  last change: $Author: vg $ $Date: 2007-09-18 13:59:47 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#include <precomp.h>
#include "hfi_typedef.hxx"

// NOT FULLY DEFINED SERVICES
#include <ary/idl/i_ce.hxx>
#include <ary/idl/ik_typedef.hxx>
#include <toolkit/hf_docentry.hxx>
#include <toolkit/hf_linachain.hxx>
#include <toolkit/hf_title.hxx>
#include "hfi_navibar.hxx"
#include "hfi_typetext.hxx"
#include "hi_linkhelper.hxx"

HF_IdlTypedef::HF_IdlTypedef( Environment &         io_rEnv,
                              Xml::Element &        o_rOut )
    :   HtmlFactory_Idl(io_rEnv, &o_rOut)
{
}

HF_IdlTypedef::~HF_IdlTypedef()
{
}

typedef ary::idl::ifc_typedef::attr TypedefAttr;

void
HF_IdlTypedef::Produce_byData( const client & i_ce ) const
{
    make_Navibar(i_ce);

    HF_TitleTable
        aTitle(CurOut());

    HF_LinkedNameChain
        aNameChain(aTitle.Add_Row());

    aNameChain.Produce_CompleteChain(Env().CurPosition(), nameChainLinker);
    produce_Title(aTitle, C_sCePrefix_Typedef, i_ce);

    HF_DocEntryList
        aTopList( aTitle.Add_Row() );
    aTopList.Produce_Term("Defining Type");

    HF_IdlTypeText
        aDefinition( Env(), aTopList.Produce_Definition(), true );
    aDefinition.Produce_byData( TypedefAttr::DefiningType(i_ce) );

    CurOut() << new Html::HorizontalLine;

    write_Docu(aTitle.Add_Row(), i_ce);
    CurOut() << new Html::HorizontalLine();
}

void
HF_IdlTypedef::make_Navibar( const client & i_ce ) const
{
    HF_IdlNavigationBar
        aNaviBar(Env(), CurOut());
    aNaviBar.Produce_CeMainRow(i_ce);

    CurOut() << new Html::HorizontalLine();
}
<commit_msg>INTEGRATION: CWS changefileheader (1.5.26); FILE MERGED 2008/03/28 16:02:06 rt 1.5.26.1: #i87441# Change license header to LPGL v3.<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: hfi_typedef.cxx,v $
 * $Revision: 1.6 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#include <precomp.h>
#include "hfi_typedef.hxx"

// NOT FULLY DEFINED SERVICES
#include <ary/idl/i_ce.hxx>
#include <ary/idl/ik_typedef.hxx>
#include <toolkit/hf_docentry.hxx>
#include <toolkit/hf_linachain.hxx>
#include <toolkit/hf_title.hxx>
#include "hfi_navibar.hxx"
#include "hfi_typetext.hxx"
#include "hi_linkhelper.hxx"

HF_IdlTypedef::HF_IdlTypedef( Environment &         io_rEnv,
                              Xml::Element &        o_rOut )
    :   HtmlFactory_Idl(io_rEnv, &o_rOut)
{
}

HF_IdlTypedef::~HF_IdlTypedef()
{
}

typedef ary::idl::ifc_typedef::attr TypedefAttr;

void
HF_IdlTypedef::Produce_byData( const client & i_ce ) const
{
    make_Navibar(i_ce);

    HF_TitleTable
        aTitle(CurOut());

    HF_LinkedNameChain
        aNameChain(aTitle.Add_Row());

    aNameChain.Produce_CompleteChain(Env().CurPosition(), nameChainLinker);
    produce_Title(aTitle, C_sCePrefix_Typedef, i_ce);

    HF_DocEntryList
        aTopList( aTitle.Add_Row() );
    aTopList.Produce_Term("Defining Type");

    HF_IdlTypeText
        aDefinition( Env(), aTopList.Produce_Definition(), true );
    aDefinition.Produce_byData( TypedefAttr::DefiningType(i_ce) );

    CurOut() << new Html::HorizontalLine;

    write_Docu(aTitle.Add_Row(), i_ce);
    CurOut() << new Html::HorizontalLine();
}

void
HF_IdlTypedef::make_Navibar( const client & i_ce ) const
{
    HF_IdlNavigationBar
        aNaviBar(Env(), CurOut());
    aNaviBar.Produce_CeMainRow(i_ce);

    CurOut() << new Html::HorizontalLine();
}
<|endoftext|>