<commit_before>/*
    This file is part of libkcal.

    Copyright (c) 2001,2004 Cornelius Schumacher <schumacher@kde.org>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    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
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to
    the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.
*/

#include <qdir.h>
#include <qfile.h>
#include <qtextstream.h>

#include <klocale.h>
#include <kdebug.h>
#include <kstandarddirs.h>

#include "event.h"
#include "todo.h"
#include "freebusy.h"
#include "icalformat.h"
#include "calendar.h"
#include "freebusycache.h"

#include "scheduler.h"

using namespace KCal;

ScheduleMessage::ScheduleMessage(IncidenceBase *incidence,int method,ScheduleMessage::Status status)
{
  mIncidence = incidence;
  mMethod = method;
  mStatus = status;
}

QString ScheduleMessage::statusName(ScheduleMessage::Status status)
{
  switch (status) {
    case PublishUpdate:
// TODO: Add string when i18n freeze is over.
//      return i18n("Updated Publish");
    case PublishNew:
      return i18n("Publish");
    case Obsolete:
      return i18n("Obsolete");
    case RequestNew:
      return i18n("New Request");
    case RequestUpdate:
      return i18n("Updated Request");
    default:
      return i18n("Unknown Status: %1").arg(QString::number(status));
  }
}

struct Scheduler::Private
{
  Private() : mFreeBusyCache( 0 ) {}

  FreeBusyCache *mFreeBusyCache;
};

Scheduler::Scheduler(Calendar *calendar)
{
  mCalendar = calendar;
  mFormat = new ICalFormat();
  mFormat->setTimeZone( calendar->timeZoneId(), !calendar->isLocalTime() );

  d = new Private;
}

Scheduler::~Scheduler()
{
  delete d;

  delete mFormat;
}

void Scheduler::setFreeBusyCache( FreeBusyCache *c )
{
  d->mFreeBusyCache = c;
}

FreeBusyCache *Scheduler::freeBusyCache() const
{
  return d->mFreeBusyCache;
}

bool Scheduler::acceptTransaction( IncidenceBase *incidence,
                                   Method method,
                                   ScheduleMessage::Status status,
                                   const QString &attendee )
{
  kdDebug(5800) << "Scheduler::acceptTransaction, method="
                << methodName( method ) << endl;

  switch (method) {
    case Publish:
      return acceptPublish(incidence, status, method);
    case Request:
      return acceptRequest( incidence, status, attendee );
    case Add:
      return acceptAdd(incidence, status);
    case Cancel:
      return acceptCancel(incidence, status);
    case Declinecounter:
      return acceptDeclineCounter(incidence, status);
    case Reply:
      return acceptReply(incidence, status, method);
    case Refresh:
      return acceptRefresh(incidence, status);
    case Counter:
      return acceptCounter(incidence, status);
    default:
      deleteTransaction(incidence);
      return false;
  }
  deleteTransaction(incidence);
  return false;
}

QString Scheduler::methodName(Method method)
{
  switch (method) {
    case Publish:
      return QString::fromLatin1("Publish");
    case Request:
      return QString::fromLatin1("Request");
    case Refresh:
      return QString::fromLatin1("Refresh");
    case Cancel:
      return QString::fromLatin1("Cancel");
    case Add:
      return QString::fromLatin1("Add");
    case Reply:
      return QString::fromLatin1("Reply");
    case Counter:
      return QString::fromLatin1("Counter");
    case Declinecounter:
      return QString::fromLatin1("Decline Counter");
    default:
      return QString::fromLatin1("Unknown");
  }
}

QString Scheduler::translatedMethodName(Method method)
{
  switch (method) {
    case Publish:
      return i18n("Publish");
    case Request:
      return i18n("Request");
    case Refresh:
      return i18n("Refresh");
    case Cancel:
      return i18n("Cancel");
    case Add:
      return i18n("Add");
    case Reply:
      return i18n("Reply");
    case Counter:
      return i18n("counter proposal","Counter");
    case Declinecounter:
      return i18n("decline counter proposal","Decline Counter");
    default:
      return i18n("Unknown");
  }
}

bool Scheduler::deleteTransaction(IncidenceBase *)
{
  return true;
}

bool Scheduler::acceptPublish( IncidenceBase *incidence,
                               ScheduleMessage::Status status, Method method )
{
  if( incidence->type() == "FreeBusy" ) {
    return acceptFreeBusy( incidence, method );
  }
  kdDebug(5800) << "Scheduler::acceptPublish, status="
            << ScheduleMessage::statusName( status ) << endl;
  Incidence *inc = static_cast<Incidence *>( incidence );
  Event *even = mCalendar->event( incidence->uid() );
  switch ( status ) {
    case ScheduleMessage::Unknown:
    case ScheduleMessage::PublishNew:
    case ScheduleMessage::PublishUpdate:
      if ( even ) {
      	if ( even->revision() <= inc->revision() ) {
	  if ( even->revision() == inc->revision() &&
	      even->lastModified() > inc->lastModified() ) {
	    deleteTransaction( incidence );
	    return false;
	  }
	  mCalendar->deleteEvent( even );
	} else {
	  deleteTransaction( incidence );
	  return false;
	}
      }
      mCalendar->addIncidence( inc );
      deleteTransaction( incidence );
      return true;
    case ScheduleMessage::Obsolete:
      return true;
    default:
      deleteTransaction( incidence );
      return false;
  }
}

bool Scheduler::acceptRequest( IncidenceBase *incidence,
                               ScheduleMessage::Status status,
                               const QString &attendee )
{
  Incidence *inc = static_cast<Incidence *>(incidence);
  if (inc->type()=="FreeBusy") {
    // reply to this request is handled in korganizer's incomingdialog
    return true;
  }

  const Incidence::List existingIncidences = mCalendar->incidencesFromSchedulingID( inc->uid() );
  kdDebug(5800) << "Scheduler::acceptRequest: found " << existingIncidences.count() << " incidences with schedulingID " << inc->schedulingID() << endl;
  Incidence::List::ConstIterator incit = existingIncidences.begin();
  for ( ; incit != existingIncidences.end() ; ++incit ) {
    Incidence* const i = *incit;
    if ( i->revision() <= inc->revision() ) {
      if ( i->revision() == inc->revision() &&
           i->lastModified() > inc->lastModified() ) {
        // This isn't an update - the found incidence was modified more recently
        deleteTransaction(incidence);
        return false;
      }
      //kdDebug(5800) << "Considering this found event:" << mFormat->toString( i ) << endl;
      // The new incidence might be an update for the found one
      if ( !i->isReadOnly() ) {
        bool isUpdate = true;
        if ( status == ScheduleMessage::RequestNew ) {
          // This is supposed to be a new request - however we want to update
          // the existing one to handle the "clicking more than once on the invitation" case.
          // So check the attendee status of the attendee.
          const KCal::Attendee::List attendees = i->attendees();
          KCal::Attendee::List::ConstIterator ait;
          for ( ait = attendees.begin(); ait != attendees.end(); ++ait ) {
            if( (*ait)->email() == attendee && (*ait)->status() == Attendee::NeedsAction ) {
              // This incidence wasn't created by me - it's probably in a shared folder
              // and meant for someone else, ignore it.
              kdDebug(5800) << "ignoring " << i->uid() << " since I'm still NeedsAction there" << endl;
              isUpdate = false;
              break;
            }
          }
        }
        if ( isUpdate ) {
          kdDebug(5800) << "replacing existing incidence " << i->uid() << endl;
          mCalendar->deleteIncidence( i );
          break; // replacing one is enough
        }
      }
    } else {
      // This isn't an update - the found incidence has a bigger revision number
      deleteTransaction(incidence);
      return false;
    }
  }

  // Move the uid to be the schedulingID and make a unique UID
  inc->setSchedulingID( inc->uid() );
  inc->setUid( CalFormat::createUniqueId() );

  mCalendar->addIncidence(inc);
  deleteTransaction(incidence);
  return true;
}

bool Scheduler::acceptAdd(IncidenceBase *incidence,ScheduleMessage::Status /* status */)
{
  deleteTransaction(incidence);
  return false;
}

bool Scheduler::acceptCancel(IncidenceBase *incidence,ScheduleMessage::Status /* status */)
{
  bool ret = false;
  Event *even = mCalendar->event(incidence->uid());
  if (even) {
    mCalendar->deleteEvent(even);
    ret = true;
  } else {
    Todo *todo = mCalendar->todo(incidence->uid());
    if (todo) {
      mCalendar->deleteTodo(todo);
      ret = true;
    }
  }
  deleteTransaction(incidence);
  return ret;
}

bool Scheduler::acceptDeclineCounter(IncidenceBase *incidence,ScheduleMessage::Status /* status */)
{
  deleteTransaction(incidence);
  return false;
}

//bool Scheduler::acceptFreeBusy(Incidence *incidence,ScheduleMessage::Status status)
//{
//  deleteTransaction(incidence);
//  return false;
//}

bool Scheduler::acceptReply(IncidenceBase *incidence,ScheduleMessage::Status /* status */, Method method)
{
  if(incidence->type()=="FreeBusy") {
    return acceptFreeBusy(incidence, method);
  }
  bool ret = false;
  Event *ev = mCalendar->event(incidence->uid());
  Todo *to = mCalendar->todo(incidence->uid());
  if (ev || to) {
    //get matching attendee in calendar
    kdDebug(5800) << "Scheduler::acceptTransaction match found!" << endl;
    Attendee::List attendeesIn = incidence->attendees();
    Attendee::List attendeesEv;
    if (ev) attendeesEv = ev->attendees();
    if (to) attendeesEv = to->attendees();
    Attendee::List::ConstIterator inIt;
    Attendee::List::ConstIterator evIt;
    for ( inIt = attendeesIn.begin(); inIt != attendeesIn.end(); ++inIt ) {
      Attendee *attIn = *inIt;
      for ( evIt = attendeesEv.begin(); evIt != attendeesEv.end(); ++evIt ) {
        Attendee *attEv = *evIt;
        if (attIn->email().lower()==attEv->email().lower()) {
          //update attendee-info
          kdDebug(5800) << "Scheduler::acceptTransaction update attendee" << endl;
          attEv->setStatus(attIn->status());
          ret = true;
        }
      }
    }
    if ( !ret ) {
      // No attendees found so far, so accept them as new optional attendees
      for ( inIt = attendeesIn.begin(); inIt != attendeesIn.end(); ++inIt ) {
        Attendee* old = (*inIt);
        Attendee* a = new Attendee( old->name(), old->email(), false,
                                    old->status(), Attendee::OptParticipant );
        if ( ev )
          ev->addAttendee( a, false );
        else
          to->addAttendee( a, false );
        ret = true;
      }
    }

    if ( ret ) {
      // We set at least one of the attendees, so the incidence changed
      // Note: This should not result in a sequence number bump
      if ( ev )
        ev->updated();
      else if ( to )
        to->updated();
    }
  } else
    kdError(5800) << "No incidence for scheduling\n";
  if (ret) deleteTransaction(incidence);
  return ret;
}

bool Scheduler::acceptRefresh(IncidenceBase *incidence,ScheduleMessage::Status /* status */)
{
  // handled in korganizer's IncomingDialog
  deleteTransaction(incidence);
  return false;
}

bool Scheduler::acceptCounter(IncidenceBase *incidence,ScheduleMessage::Status /* status */)
{
  deleteTransaction(incidence);
  return false;
}

bool Scheduler::acceptFreeBusy(IncidenceBase *incidence, Method method)
{
  if ( !d->mFreeBusyCache ) {
    kdError() << "KCal::Scheduler: no FreeBusyCache." << endl;
    return false;
  }

  FreeBusy *freebusy = static_cast<FreeBusy *>(incidence);

  kdDebug(5800) << "acceptFreeBusy:: freeBusyDirName: " << freeBusyDir() << endl;

  Person from;
  if(method == Scheduler::Publish) {
    from = freebusy->organizer();
  }
  if((method == Scheduler::Reply) && (freebusy->attendeeCount() == 1)) {
    Attendee *attendee = freebusy->attendees().first();
    from = attendee->email();
  }

  if ( !d->mFreeBusyCache->saveFreeBusy( freebusy, from ) ) return false;

  deleteTransaction(incidence);
  return true;
}
<commit_msg>More debug output (to get more info out of michel)<commit_after>/*
    This file is part of libkcal.

    Copyright (c) 2001,2004 Cornelius Schumacher <schumacher@kde.org>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    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
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to
    the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.
*/

#include <qdir.h>
#include <qfile.h>
#include <qtextstream.h>

#include <klocale.h>
#include <kdebug.h>
#include <kstandarddirs.h>

#include "event.h"
#include "todo.h"
#include "freebusy.h"
#include "icalformat.h"
#include "calendar.h"
#include "freebusycache.h"

#include "scheduler.h"

using namespace KCal;

ScheduleMessage::ScheduleMessage(IncidenceBase *incidence,int method,ScheduleMessage::Status status)
{
  mIncidence = incidence;
  mMethod = method;
  mStatus = status;
}

QString ScheduleMessage::statusName(ScheduleMessage::Status status)
{
  switch (status) {
    case PublishUpdate:
// TODO: Add string when i18n freeze is over.
//      return i18n("Updated Publish");
    case PublishNew:
      return i18n("Publish");
    case Obsolete:
      return i18n("Obsolete");
    case RequestNew:
      return i18n("New Request");
    case RequestUpdate:
      return i18n("Updated Request");
    default:
      return i18n("Unknown Status: %1").arg(QString::number(status));
  }
}

struct Scheduler::Private
{
  Private() : mFreeBusyCache( 0 ) {}

  FreeBusyCache *mFreeBusyCache;
};

Scheduler::Scheduler(Calendar *calendar)
{
  mCalendar = calendar;
  mFormat = new ICalFormat();
  mFormat->setTimeZone( calendar->timeZoneId(), !calendar->isLocalTime() );

  d = new Private;
}

Scheduler::~Scheduler()
{
  delete d;

  delete mFormat;
}

void Scheduler::setFreeBusyCache( FreeBusyCache *c )
{
  d->mFreeBusyCache = c;
}

FreeBusyCache *Scheduler::freeBusyCache() const
{
  return d->mFreeBusyCache;
}

bool Scheduler::acceptTransaction( IncidenceBase *incidence,
                                   Method method,
                                   ScheduleMessage::Status status,
                                   const QString &attendee )
{
  kdDebug(5800) << "Scheduler::acceptTransaction, method="
                << methodName( method ) << endl;

  switch (method) {
    case Publish:
      return acceptPublish(incidence, status, method);
    case Request:
      return acceptRequest( incidence, status, attendee );
    case Add:
      return acceptAdd(incidence, status);
    case Cancel:
      return acceptCancel(incidence, status);
    case Declinecounter:
      return acceptDeclineCounter(incidence, status);
    case Reply:
      return acceptReply(incidence, status, method);
    case Refresh:
      return acceptRefresh(incidence, status);
    case Counter:
      return acceptCounter(incidence, status);
    default:
      deleteTransaction(incidence);
      return false;
  }
  deleteTransaction(incidence);
  return false;
}

QString Scheduler::methodName(Method method)
{
  switch (method) {
    case Publish:
      return QString::fromLatin1("Publish");
    case Request:
      return QString::fromLatin1("Request");
    case Refresh:
      return QString::fromLatin1("Refresh");
    case Cancel:
      return QString::fromLatin1("Cancel");
    case Add:
      return QString::fromLatin1("Add");
    case Reply:
      return QString::fromLatin1("Reply");
    case Counter:
      return QString::fromLatin1("Counter");
    case Declinecounter:
      return QString::fromLatin1("Decline Counter");
    default:
      return QString::fromLatin1("Unknown");
  }
}

QString Scheduler::translatedMethodName(Method method)
{
  switch (method) {
    case Publish:
      return i18n("Publish");
    case Request:
      return i18n("Request");
    case Refresh:
      return i18n("Refresh");
    case Cancel:
      return i18n("Cancel");
    case Add:
      return i18n("Add");
    case Reply:
      return i18n("Reply");
    case Counter:
      return i18n("counter proposal","Counter");
    case Declinecounter:
      return i18n("decline counter proposal","Decline Counter");
    default:
      return i18n("Unknown");
  }
}

bool Scheduler::deleteTransaction(IncidenceBase *)
{
  return true;
}

bool Scheduler::acceptPublish( IncidenceBase *incidence,
                               ScheduleMessage::Status status, Method method )
{
  if( incidence->type() == "FreeBusy" ) {
    return acceptFreeBusy( incidence, method );
  }
  kdDebug(5800) << "Scheduler::acceptPublish, status="
            << ScheduleMessage::statusName( status ) << endl;
  Incidence *inc = static_cast<Incidence *>( incidence );
  Event *even = mCalendar->event( incidence->uid() );
  switch ( status ) {
    case ScheduleMessage::Unknown:
    case ScheduleMessage::PublishNew:
    case ScheduleMessage::PublishUpdate:
      if ( even ) {
      	if ( even->revision() <= inc->revision() ) {
	  if ( even->revision() == inc->revision() &&
	      even->lastModified() > inc->lastModified() ) {
	    deleteTransaction( incidence );
	    return false;
	  }
	  mCalendar->deleteEvent( even );
	} else {
	  deleteTransaction( incidence );
	  return false;
	}
      }
      mCalendar->addIncidence( inc );
      deleteTransaction( incidence );
      return true;
    case ScheduleMessage::Obsolete:
      return true;
    default:
      deleteTransaction( incidence );
      return false;
  }
}

bool Scheduler::acceptRequest( IncidenceBase *incidence,
                               ScheduleMessage::Status status,
                               const QString &attendee )
{
  Incidence *inc = static_cast<Incidence *>(incidence);
  if (inc->type()=="FreeBusy") {
    // reply to this request is handled in korganizer's incomingdialog
    return true;
  }

  const Incidence::List existingIncidences = mCalendar->incidencesFromSchedulingID( inc->uid() );
  kdDebug(5800) << "Scheduler::acceptRequest: found " << existingIncidences.count() << " incidences with schedulingID " << inc->schedulingID() << endl;
  Incidence::List::ConstIterator incit = existingIncidences.begin();
  for ( ; incit != existingIncidences.end() ; ++incit ) {
    Incidence* const i = *incit;
    kdDebug(5800) << "Considering this found event ("
                  << ( i->isReadOnly() ? "readonly" : "readwrite" )
                  << ") :" << mFormat->toString( i ) << endl;
    if ( i->revision() <= inc->revision() ) {
      if ( i->revision() == inc->revision() &&
           i->lastModified() > inc->lastModified() ) {
        // This isn't an update - the found incidence was modified more recently
        kdDebug(5800) << "This isn't an update - the found incidence was modified more recently" << endl;
        deleteTransaction(incidence);
        return false;
      }
      // The new incidence might be an update for the found one
      if ( !i->isReadOnly() ) {
        bool isUpdate = true;
        if ( status == ScheduleMessage::RequestNew ) {
          kdDebug(5800) << "looking in " << i->uid() << "'s attendees" << endl;
          // This is supposed to be a new request - however we want to update
          // the existing one to handle the "clicking more than once on the invitation" case.
          // So check the attendee status of the attendee.
          const KCal::Attendee::List attendees = i->attendees();
          KCal::Attendee::List::ConstIterator ait;
          for ( ait = attendees.begin(); ait != attendees.end(); ++ait ) {
            if( (*ait)->email() == attendee && (*ait)->status() == Attendee::NeedsAction ) {
              // This incidence wasn't created by me - it's probably in a shared folder
              // and meant for someone else, ignore it.
              kdDebug(5800) << "ignoring " << i->uid() << " since I'm still NeedsAction there" << endl;
              isUpdate = false;
              break;
            }
          }
        }
        if ( isUpdate ) {
          kdDebug(5800) << "replacing existing incidence " << i->uid() << endl;
          mCalendar->deleteIncidence( i );
          break; // replacing one is enough
        }
      }
    } else {
      // This isn't an update - the found incidence has a bigger revision number
      kdDebug(5800) << "This isn't an update - the found incidence has a bigger revision number" << endl;
      deleteTransaction(incidence);
      return false;
    }
  }

  // Move the uid to be the schedulingID and make a unique UID
  inc->setSchedulingID( inc->uid() );
  inc->setUid( CalFormat::createUniqueId() );
  kdDebug(5800) << "Storing new incidence with scheduling uid=" << inc->schedulingID() << " and uid=" << inc->uid() << endl;

  mCalendar->addIncidence(inc);
  deleteTransaction(incidence);
  return true;
}

bool Scheduler::acceptAdd(IncidenceBase *incidence,ScheduleMessage::Status /* status */)
{
  deleteTransaction(incidence);
  return false;
}

bool Scheduler::acceptCancel(IncidenceBase *incidence,ScheduleMessage::Status /* status */)
{
  bool ret = false;
  Event *even = mCalendar->event(incidence->uid());
  if (even) {
    mCalendar->deleteEvent(even);
    ret = true;
  } else {
    Todo *todo = mCalendar->todo(incidence->uid());
    if (todo) {
      mCalendar->deleteTodo(todo);
      ret = true;
    }
  }
  deleteTransaction(incidence);
  return ret;
}

bool Scheduler::acceptDeclineCounter(IncidenceBase *incidence,ScheduleMessage::Status /* status */)
{
  deleteTransaction(incidence);
  return false;
}

//bool Scheduler::acceptFreeBusy(Incidence *incidence,ScheduleMessage::Status status)
//{
//  deleteTransaction(incidence);
//  return false;
//}

bool Scheduler::acceptReply(IncidenceBase *incidence,ScheduleMessage::Status /* status */, Method method)
{
  if(incidence->type()=="FreeBusy") {
    return acceptFreeBusy(incidence, method);
  }
  bool ret = false;
  Event *ev = mCalendar->event(incidence->uid());
  Todo *to = mCalendar->todo(incidence->uid());
  if (ev || to) {
    //get matching attendee in calendar
    kdDebug(5800) << "Scheduler::acceptTransaction match found!" << endl;
    Attendee::List attendeesIn = incidence->attendees();
    Attendee::List attendeesEv;
    if (ev) attendeesEv = ev->attendees();
    if (to) attendeesEv = to->attendees();
    Attendee::List::ConstIterator inIt;
    Attendee::List::ConstIterator evIt;
    for ( inIt = attendeesIn.begin(); inIt != attendeesIn.end(); ++inIt ) {
      Attendee *attIn = *inIt;
      for ( evIt = attendeesEv.begin(); evIt != attendeesEv.end(); ++evIt ) {
        Attendee *attEv = *evIt;
        if (attIn->email().lower()==attEv->email().lower()) {
          //update attendee-info
          kdDebug(5800) << "Scheduler::acceptTransaction update attendee" << endl;
          attEv->setStatus(attIn->status());
          ret = true;
        }
      }
    }
    if ( !ret ) {
      // No attendees found so far, so accept them as new optional attendees
      for ( inIt = attendeesIn.begin(); inIt != attendeesIn.end(); ++inIt ) {
        Attendee* old = (*inIt);
        Attendee* a = new Attendee( old->name(), old->email(), false,
                                    old->status(), Attendee::OptParticipant );
        if ( ev )
          ev->addAttendee( a, false );
        else
          to->addAttendee( a, false );
        ret = true;
      }
    }

    if ( ret ) {
      // We set at least one of the attendees, so the incidence changed
      // Note: This should not result in a sequence number bump
      if ( ev )
        ev->updated();
      else if ( to )
        to->updated();
    }
  } else
    kdError(5800) << "No incidence for scheduling\n";
  if (ret) deleteTransaction(incidence);
  return ret;
}

bool Scheduler::acceptRefresh(IncidenceBase *incidence,ScheduleMessage::Status /* status */)
{
  // handled in korganizer's IncomingDialog
  deleteTransaction(incidence);
  return false;
}

bool Scheduler::acceptCounter(IncidenceBase *incidence,ScheduleMessage::Status /* status */)
{
  deleteTransaction(incidence);
  return false;
}

bool Scheduler::acceptFreeBusy(IncidenceBase *incidence, Method method)
{
  if ( !d->mFreeBusyCache ) {
    kdError() << "KCal::Scheduler: no FreeBusyCache." << endl;
    return false;
  }

  FreeBusy *freebusy = static_cast<FreeBusy *>(incidence);

  kdDebug(5800) << "acceptFreeBusy:: freeBusyDirName: " << freeBusyDir() << endl;

  Person from;
  if(method == Scheduler::Publish) {
    from = freebusy->organizer();
  }
  if((method == Scheduler::Reply) && (freebusy->attendeeCount() == 1)) {
    Attendee *attendee = freebusy->attendees().first();
    from = attendee->email();
  }

  if ( !d->mFreeBusyCache->saveFreeBusy( freebusy, from ) ) return false;

  deleteTransaction(incidence);
  return true;
}
<|endoftext|>


<commit_before>namespace RegularExpressionMatching {
    class Solution {
    public:
        bool checkIsMatch(const char *s, int posS, const char * p, int posP) {
            if (s[posS] == '\0' && p[posP] == '\0') { // sample case: s="", p=""
                return true;
            }

            if (s[posS] == '\0' && p[posP] != '\0') {
                if (p[posP + 1] == '*') { // sample case: s="", p="c*a*"
                    return checkIsMatch(s, posS, p, posP + 2);
                } else {
                    return false; // sample case: s="", p="a"
                }
            }

            if (s[posS] != '\0' && p[posP] == '\0') {
                return false; // sample case: s="abc", p=""
            }

            if (p[posP + 1] == '*') {
                bool res = checkIsMatch(s, posS, p, posP + 2);
                if (res) return res;

                int i = 1;
                if (p[posP] != '.' && p[posP] == s[posS]) { // sample case: s="aaaab", p="a*b"
                    while (s[posS + i] == s[posS]) {
                        bool res = checkIsMatch(s, posS + i, p, posP + 2);
                        if (res) {
                            return res;
                        }
                        i++;
                    }
                } else if (p[posP] == '.') { // sample case: s="abcde", p=".*e"
                    while (s[posS + i] != '\0') {
                        bool res = checkIsMatch(s, posS + i, p, posP + 2);
                        if (res) {
                            return res;
                        }
                        i++;
                    }
                } else {
                    return false; // sample case: s="abcde", p="d*e"
                }
                return checkIsMatch(s, posS + i, p, posP + 2);
            } else {
                if (s[posS] == p[posP] || p[posP] == '.') { // sample case: s="abcde", p=".bcde" or s="abcde", p="abcde"
                    return checkIsMatch(s, posS + 1, p, posP + 1);
                } else {
                    return false;
                }
            }
        }

        bool isMatch(const char *s, const char *p) {
            if (s == NULL || p == NULL) {
                return false;
            }

            return checkIsMatch(s, 0, p, 0);
        }
    };

    // ----------------------------------------------------------------
    // add DP solution
    // ----------------------------------------------------------------
    class Solution {
    public:
        bool isMatch(const char *s, const char *p) {
            int sLen = strlen(s);
            int pLen = strlen(p);

            vector<vector<bool> > dp(sLen + 1, vector<bool>(pLen + 1, false));
            dp[0][0] = true;

            for (int i = 1; i <= pLen; i++) {
                if (p[i - 1] == '*') dp[0][i] = dp[0][i - 2]; // we assume that the invalid pattern with only a "*" won't appear
            }

            for (int i = 1; i <= sLen; i++) {
                for (int j = 1; j <= pLen; j++) {
                    char cS = s[i - 1];
                    char cP = p[j - 1];
                    if (cS == cP || cP == '.') {
                        dp[i][j] = dp[i - 1][j - 1];
                    } else if (cP == '*') {
                        char cPPrev = p[j - 2];
                        if (cPPrev != cS && cPPrev != '.') {
                            dp[i][j] = dp[i][j - 2];
                        } else {
                            dp[i][j] = dp[i][j - 2] | dp[i - 1][j];
                        }
                    }
                }
            }

            return dp[sLen][pLen];
        }
    };
}
<commit_msg>Add concise recursive solution<commit_after>namespace RegularExpressionMatching {
    class Solution {
    public:
        bool checkIsMatch(const char *s, int posS, const char * p, int posP) {
            if (s[posS] == '\0' && p[posP] == '\0') { // sample case: s="", p=""
                return true;
            }

            if (s[posS] == '\0' && p[posP] != '\0') {
                if (p[posP + 1] == '*') { // sample case: s="", p="c*a*"
                    return checkIsMatch(s, posS, p, posP + 2);
                } else {
                    return false; // sample case: s="", p="a"
                }
            }

            if (s[posS] != '\0' && p[posP] == '\0') {
                return false; // sample case: s="abc", p=""
            }

            if (p[posP + 1] == '*') {
                bool res = checkIsMatch(s, posS, p, posP + 2);
                if (res) return res;

                int i = 1;
                if (p[posP] != '.' && p[posP] == s[posS]) { // sample case: s="aaaab", p="a*b"
                    while (s[posS + i] == s[posS]) {
                        bool res = checkIsMatch(s, posS + i, p, posP + 2);
                        if (res) {
                            return res;
                        }
                        i++;
                    }
                } else if (p[posP] == '.') { // sample case: s="abcde", p=".*e"
                    while (s[posS + i] != '\0') {
                        bool res = checkIsMatch(s, posS + i, p, posP + 2);
                        if (res) {
                            return res;
                        }
                        i++;
                    }
                } else {
                    return false; // sample case: s="abcde", p="d*e"
                }
                return checkIsMatch(s, posS + i, p, posP + 2);
            } else {
                if (s[posS] == p[posP] || p[posP] == '.') { // sample case: s="abcde", p=".bcde" or s="abcde", p="abcde"
                    return checkIsMatch(s, posS + 1, p, posP + 1);
                } else {
                    return false;
                }
            }
        }

        bool isMatch(const char *s, const char *p) {
            if (s == NULL || p == NULL) {
                return false;
            }

            return checkIsMatch(s, 0, p, 0);
        }
    };

    // ----------------------------------------------------------------
    // More concise recursive solution
    // ----------------------------------------------------------------
    class Solution {
    public:

        bool isMatch(const char *s, const char *p) {
            assert(s && p);
            if (*p == '\0') return *s == '\0';

            // next char is not '*': must match current character
            if (*(p+1) != '*') {
                assert(*p != '*');
                return ((*p == *s) || (*p == '.' && *s != '\0')) && isMatch(s+1, p+1);
            }
            // next char is '*'
            while ((*p == *s) || (*p == '.' && *s != '\0')) {
                if (isMatch(s, p+2)) return true;
                s++;
            }
            return isMatch(s, p+2);
        }
    };

    // ----------------------------------------------------------------
    // add DP solution
    // ----------------------------------------------------------------
    class Solution {
    public:
        bool isMatch(const char *s, const char *p) {
            int sLen = strlen(s);
            int pLen = strlen(p);

            vector<vector<bool> > dp(sLen + 1, vector<bool>(pLen + 1, false));
            dp[0][0] = true;

            for (int i = 1; i <= pLen; i++) {
                if (p[i - 1] == '*') dp[0][i] = dp[0][i - 2]; // we assume that the invalid pattern with only a "*" won't appear
            }

            for (int i = 1; i <= sLen; i++) {
                for (int j = 1; j <= pLen; j++) {
                    char cS = s[i - 1];
                    char cP = p[j - 1];
                    if (cS == cP || cP == '.') {
                        dp[i][j] = dp[i - 1][j - 1];
                    } else if (cP == '*') {
                        char cPPrev = p[j - 2];
                        if (cPPrev != cS && cPPrev != '.') {
                            dp[i][j] = dp[i][j - 2];
                        } else {
                            dp[i][j] = dp[i][j - 2] | dp[i - 1][j];
                        }
                    }
                }
            }

            return dp[sLen][pLen];
        }
    };
}
<|endoftext|>


<commit_before>/** \file    apply_differential_update.cc
 *  \brief   A tool for applying a differential update to a complete MARC dump.
 *  \author  Dr. Johannes Ruscheinski
 */

/*
    Copyright (C) 2018-2020 Library of the University of Tübingen

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as
    published by the Free Software Foundation, either version 3 of the
    License, or (at your option) any later version.

    This program 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 Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <iostream>
#include <map>
#include <stdexcept>
#include <unordered_set>
#include <cassert>
#include <cstdlib>
#include <cstring>
#include "Archive.h"
#include "BSZUtil.h"
#include "Compiler.h"
#include "FileUtil.h"
#include "LocalDataDB.h"
#include "MARC.h"
#include "StringUtil.h"
#include "util.h"

namespace {

[[noreturn]] void Usage() {
    ::Usage("[--min-log-level=log_level] [--keep-intermediate-files] input_directory "
            "difference_archive output_directory\n"
            "       Log levels are DEBUG, INFO, WARNING and ERROR with INFO being the default.\n");
    std::exit(EXIT_FAILURE);
}

void CopyAndCollectPPNs(LocalDataDB * const local_data_db, MARC::Reader * const reader, MARC::Writer * const writer,
                        std::unordered_set<std::string> * const previously_seen_ppns)
{
    while (auto record = reader->read()) {
        const auto PPN(record.getControlNumber());
        if (previously_seen_ppns->find(PPN) == previously_seen_ppns->end()) {
            const auto first_local_field(record.findTag("LOK"));
            if (unlikely(first_local_field != record.end())) {
                std::vector<std::string> local_fields;
                auto local_field(first_local_field);
                while (local_field != record.end())
                    local_fields.emplace_back(local_field->getContents());
                local_data_db->insertOrReplace(PPN, local_fields);

                record.truncate(first_local_field);
            }

            previously_seen_ppns->emplace(PPN);
            if (record.getFirstField("ORI") == record.end())
                record.insertField("ORI", 'a', FileUtil::GetLastPathComponent(reader->getPath()));
            writer->write(record);
        }
    }
}

void CopySelectedTypes(LocalDataDB * const local_data_db, const std::vector<std::string> &archive_members, MARC::Writer * const writer,
                       const std::set<BSZUtil::ArchiveType> &selected_types, std::unordered_set<std::string> * const previously_seen_ppns)
{
    for (const auto &archive_member : archive_members) {
        if (selected_types.find(BSZUtil::GetArchiveType(archive_member)) != selected_types.cend()) {
            const auto reader(MARC::Reader::Factory(archive_member, MARC::FileType::BINARY));
            CopyAndCollectPPNs(local_data_db, reader.get(), writer, previously_seen_ppns);
        }
    }
}

void PatchArchiveMembersAndCreateOutputArchive(LocalDataDB * const local_data_db, const std::vector<std::string> &input_archive_members,
                                               const std::vector<std::string> &difference_archive_members, const std::string &output_directory)
{
    if (input_archive_members.empty())
        LOG_ERROR("no input archive members!");
    if (difference_archive_members.empty())
        LOG_WARNING("no difference archive members!");

    //
    // We process title data first and combine all inferior and superior records.
    //

    const auto title_writer(MARC::Writer::Factory(output_directory + "/tit.mrc", MARC::FileType::BINARY));
    std::unordered_set<std::string> previously_seen_title_ppns;
    CopySelectedTypes(local_data_db, difference_archive_members, title_writer.get(), { BSZUtil::TITLE_RECORDS, BSZUtil::SUPERIOR_TITLES },
                      &previously_seen_title_ppns);
    CopySelectedTypes(local_data_db, input_archive_members, title_writer.get(), { BSZUtil::TITLE_RECORDS, BSZUtil::SUPERIOR_TITLES },
                      &previously_seen_title_ppns);

    const auto authority_writer(MARC::Writer::Factory(output_directory + "/aut.mrc", MARC::FileType::BINARY));
    std::unordered_set<std::string> previously_seen_authority_ppns;
    CopySelectedTypes(local_data_db, difference_archive_members, authority_writer.get(), { BSZUtil::AUTHORITY_RECORDS },
                      &previously_seen_authority_ppns);
    CopySelectedTypes(local_data_db, input_archive_members, authority_writer.get(), { BSZUtil::AUTHORITY_RECORDS },
                      &previously_seen_authority_ppns);
}

void GetDirectoryContentsWithRelativepath(const std::string &archive_name, std::vector<std::string> * const archive_members) {
    const std::string directory_name(archive_name);
    FileUtil::GetFileNameList(".(raw|mrc)$", archive_members, directory_name);
    for (auto &archive_member : *archive_members)
        archive_member = directory_name + "/" + archive_member;
}

std::string RemoveSuffix(const std::string &s, const std::string &suffix) {
    if (unlikely(not StringUtil::EndsWith(s, suffix)))
        LOG_ERROR("\"" + s + "\" does not end w/ \"" + suffix + "\"!");
    return s.substr(0, s.length() - suffix.length());
}

inline std::string StripTarGz(const std::string &archive_filename) {
    return RemoveSuffix(archive_filename, ".tar.gz");
}

} // unnamed namespace

int Main(int argc, char *argv[]) {
    if (argc < 4)
        Usage();

    bool keep_intermediate_files(false);
    if (std::strcmp(argv[1], "--keep-intermediate-files") == 0) {
        keep_intermediate_files = true;
        --argc, ++argv;
    }

    if (argc != 4)
        Usage();

    const std::string input_directory(FileUtil::MakeAbsolutePath(argv[1]));
    const std::string difference_archive(FileUtil::MakeAbsolutePath(argv[2]));
    const std::string output_directory(FileUtil::MakeAbsolutePath(argv[3]));

    if (input_directory == difference_archive or input_directory == output_directory or difference_archive == output_directory)
        LOG_ERROR("all archive names must be distinct!");

    std::unique_ptr<FileUtil::AutoTempDirectory> working_directory;
    const std::string difference_directory(StripTarGz(difference_archive));
    Archive::UnpackArchive(difference_archive, difference_directory);
    if (not FileUtil::MakeDirectory(output_directory))
        LOG_ERROR("failed to create directory: \"" + output_directory + "\"!");

    std::vector<std::string> input_archive_members, difference_archive_members;
    GetDirectoryContentsWithRelativepath(input_directory, &input_archive_members);
    GetDirectoryContentsWithRelativepath(StripTarGz(difference_archive), &difference_archive_members);

    LocalDataDB local_data_db(LocalDataDB::READ_WRITE);
    PatchArchiveMembersAndCreateOutputArchive(&local_data_db, input_archive_members, difference_archive_members, output_directory);

    if (not keep_intermediate_files and not FileUtil::RemoveDirectory(difference_directory))
        LOG_ERROR("failed to remove directory: \"" + difference_directory + "\"!");

    return EXIT_SUCCESS;
}
<commit_msg>Fixed an infinite-loop bug.<commit_after>/** \file    apply_differential_update.cc
 *  \brief   A tool for applying a differential update to a complete MARC dump.
 *  \author  Dr. Johannes Ruscheinski
 */

/*
    Copyright (C) 2018-2020 Library of the University of Tübingen

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as
    published by the Free Software Foundation, either version 3 of the
    License, or (at your option) any later version.

    This program 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 Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <iostream>
#include <map>
#include <stdexcept>
#include <unordered_set>
#include <cassert>
#include <cstdlib>
#include <cstring>
#include "Archive.h"
#include "BSZUtil.h"
#include "Compiler.h"
#include "FileUtil.h"
#include "LocalDataDB.h"
#include "MARC.h"
#include "StringUtil.h"
#include "util.h"

namespace {

[[noreturn]] void Usage() {
    ::Usage("[--min-log-level=log_level] [--keep-intermediate-files] input_directory "
            "difference_archive output_directory\n"
            "       Log levels are DEBUG, INFO, WARNING and ERROR with INFO being the default.\n");
}

void CopyAndCollectPPNs(LocalDataDB * const local_data_db, MARC::Reader * const reader, MARC::Writer * const writer,
                        std::unordered_set<std::string> * const previously_seen_ppns)
{
    while (auto record = reader->read()) {
        const auto PPN(record.getControlNumber());
        if (previously_seen_ppns->find(PPN) == previously_seen_ppns->end()) {
            const auto first_local_field(record.findTag("LOK"));
            if (unlikely(first_local_field != record.end())) {
                std::vector<std::string> local_fields;
                for (auto local_field(first_local_field); local_field != record.end(); ++local_field)
                    local_fields.emplace_back(local_field->getContents());
                local_data_db->insertOrReplace(PPN, local_fields);

                record.truncate(first_local_field);
            }

            previously_seen_ppns->emplace(PPN);
            if (record.getFirstField("ORI") == record.end())
                record.insertField("ORI", 'a', FileUtil::GetLastPathComponent(reader->getPath()));
            writer->write(record);
        }
    }
}

void CopySelectedTypes(LocalDataDB * const local_data_db, const std::vector<std::string> &archive_members, MARC::Writer * const writer,
                       const std::set<BSZUtil::ArchiveType> &selected_types, std::unordered_set<std::string> * const previously_seen_ppns)
{
    for (const auto &archive_member : archive_members) {
        if (selected_types.find(BSZUtil::GetArchiveType(archive_member)) != selected_types.cend()) {
            const auto reader(MARC::Reader::Factory(archive_member, MARC::FileType::BINARY));
            CopyAndCollectPPNs(local_data_db, reader.get(), writer, previously_seen_ppns);
        }
    }
}

void PatchArchiveMembersAndCreateOutputArchive(LocalDataDB * const local_data_db, const std::vector<std::string> &input_archive_members,
                                               const std::vector<std::string> &difference_archive_members, const std::string &output_directory)
{
    if (input_archive_members.empty())
        LOG_ERROR("no input archive members!");
    if (difference_archive_members.empty())
        LOG_WARNING("no difference archive members!");

    //
    // We process title data first and combine all inferior and superior records.
    //

    const auto title_writer(MARC::Writer::Factory(output_directory + "/tit.mrc", MARC::FileType::BINARY));
    std::unordered_set<std::string> previously_seen_title_ppns;
    CopySelectedTypes(local_data_db, difference_archive_members, title_writer.get(), { BSZUtil::TITLE_RECORDS, BSZUtil::SUPERIOR_TITLES },
                      &previously_seen_title_ppns);
    CopySelectedTypes(local_data_db, input_archive_members, title_writer.get(), { BSZUtil::TITLE_RECORDS, BSZUtil::SUPERIOR_TITLES },
                      &previously_seen_title_ppns);

    const auto authority_writer(MARC::Writer::Factory(output_directory + "/aut.mrc", MARC::FileType::BINARY));
    std::unordered_set<std::string> previously_seen_authority_ppns;
    CopySelectedTypes(local_data_db, difference_archive_members, authority_writer.get(), { BSZUtil::AUTHORITY_RECORDS },
                      &previously_seen_authority_ppns);
    CopySelectedTypes(local_data_db, input_archive_members, authority_writer.get(), { BSZUtil::AUTHORITY_RECORDS },
                      &previously_seen_authority_ppns);
}

void GetDirectoryContentsWithRelativepath(const std::string &archive_name, std::vector<std::string> * const archive_members) {
    const std::string directory_name(archive_name);
    FileUtil::GetFileNameList(".(raw|mrc)$", archive_members, directory_name);
    for (auto &archive_member : *archive_members)
        archive_member = directory_name + "/" + archive_member;
}

std::string RemoveSuffix(const std::string &s, const std::string &suffix) {
    if (unlikely(not StringUtil::EndsWith(s, suffix)))
        LOG_ERROR("\"" + s + "\" does not end w/ \"" + suffix + "\"!");
    return s.substr(0, s.length() - suffix.length());
}

inline std::string StripTarGz(const std::string &archive_filename) {
    return RemoveSuffix(archive_filename, ".tar.gz");
}

} // unnamed namespace

int Main(int argc, char *argv[]) {
    if (argc < 4)
        Usage();

    bool keep_intermediate_files(false);
    if (std::strcmp(argv[1], "--keep-intermediate-files") == 0) {
        keep_intermediate_files = true;
        --argc, ++argv;
    }

    if (argc != 4)
        Usage();

    const std::string input_directory(FileUtil::MakeAbsolutePath(argv[1]));
    const std::string difference_archive(FileUtil::MakeAbsolutePath(argv[2]));
    const std::string output_directory(FileUtil::MakeAbsolutePath(argv[3]));

    if (input_directory == difference_archive or input_directory == output_directory or difference_archive == output_directory)
        LOG_ERROR("all archive names must be distinct!");

    std::unique_ptr<FileUtil::AutoTempDirectory> working_directory;
    const std::string difference_directory(StripTarGz(difference_archive));
    Archive::UnpackArchive(difference_archive, difference_directory);
    if (not FileUtil::MakeDirectory(output_directory))
        LOG_ERROR("failed to create directory: \"" + output_directory + "\"!");

    std::vector<std::string> input_archive_members, difference_archive_members;
    GetDirectoryContentsWithRelativepath(input_directory, &input_archive_members);
    GetDirectoryContentsWithRelativepath(StripTarGz(difference_archive), &difference_archive_members);

    LocalDataDB local_data_db(LocalDataDB::READ_WRITE);
    PatchArchiveMembersAndCreateOutputArchive(&local_data_db, input_archive_members, difference_archive_members, output_directory);

    if (not keep_intermediate_files and not FileUtil::RemoveDirectory(difference_directory))
        LOG_ERROR("failed to remove directory: \"" + difference_directory + "\"!");

    return EXIT_SUCCESS;
}
<|endoftext|>


<commit_before>// Copyright 2016-2020 Francesco Biscani (bluescarni@gmail.com)
//
// This file is part of the mp++ library.
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.

#include <ostream>
#include <sstream>
#include <stdexcept>
#include <string>

// NOTE: extern "C" is already included in quadmath.h since GCC 4.8:
// https://stackoverflow.com/questions/13780219/link-libquadmath-with-c-on-linux
#include <quadmath.h>

#include <mp++/config.hpp>
#include <mp++/detail/utils.hpp>
#include <mp++/real128.hpp>

namespace mppp
{

// Double check our assumption regarding
// the number of binary digits in the
// significand.
static_assert(FLT128_MANT_DIG == real128_sig_digits(), "Invalid number of digits.");

namespace detail
{

void float128_stream(std::ostream &os, const __float128 &x)
{
    char buf[100];
    // NOTE: 36 decimal digits ensures that reading back the string always produces the same value.
    // https://en.wikipedia.org/wiki/Quadruple-precision_floating-point_format
    // NOTE: when using the g/G format, the precision field represent the number
    // of significant digits:
    // https://linux.die.net/man/3/printf
    const auto n = ::quadmath_snprintf(buf, sizeof(buf), "%.36Qg", x);
    // LCOV_EXCL_START
    if (mppp_unlikely(n < 0)) {
        throw std::runtime_error("A call to quadmath_snprintf() failed: a negative exit status of " + to_string(n)
                                 + " was returned");
    }
    if (mppp_unlikely(unsigned(n) >= sizeof(buf))) {
        throw std::runtime_error("A call to quadmath_snprintf() failed: the exit status " + to_string(n)
                                 + " is not less than the size of the internal buffer " + to_string(sizeof(buf)));
    }
    // LCOV_EXCL_STOP
    os << &buf[0];
}

__float128 str_to_float128(const char *s)
{
    char *endptr;
    auto retval = ::strtoflt128(s, &endptr);
    if (mppp_unlikely(endptr == s || *endptr != '\0')) {
        // NOTE: the first condition handles an empty string.
        // endptr will point to the first character in the string which
        // did not contribute to the construction of retval.
        throw std::invalid_argument("The string '" + std::string(s)
                                    + "' does not represent a valid quadruple-precision floating-point value");
    }
    return retval;
}

__float128 scalbnq(__float128 x, int exp)
{
    return ::scalbnq(x, exp);
}

__float128 scalblnq(__float128 x, long exp)
{
    return ::scalblnq(x, exp);
}

__float128 powq(__float128 x, __float128 y)
{
    return ::powq(x, y);
}

} // namespace detail

/// Constructor from range of characters.
/**
 * This constructor will initialise \p this from the content of the input half-open range, which is interpreted
 * as the string representation of a floating-point value.
 *
 * Internally, the constructor will copy the content of the range to a local buffer, add a string terminator, and
 * invoke the constructor from string.
 *
 * @param begin the begin of the input range.
 * @param end the end of the input range.
 *
 * @throws unspecified any exception thrown by the constructor from string or by memory errors in standard
 * containers.
 */
real128::real128(const char *begin, const char *end)
{
    MPPP_MAYBE_TLS std::vector<char> buffer;
    buffer.assign(begin, end);
    buffer.emplace_back('\0');
    m_value = detail::str_to_float128(buffer.data());
}

/// Convert to string.
/**
 * \rststar
 * This method will convert ``this`` to a decimal string representation in scientific format.
 * The number of significant digits in the output (36) guarantees that a :cpp:class:`~mppp::real128`
 * constructed from the returned string will have a value identical to the value of ``this``.
 *
 * The implementation uses the ``quadmath_snprintf()`` function from the quadmath library.
 *
 * .. seealso::
 *    https://gcc.gnu.org/onlinedocs/libquadmath/quadmath_005fsnprintf.html
 * \endrststar
 *
 * @return a decimal string representation of ``this``.
 *
 * @throws std::runtime_error if the internal call to the ``quadmath_snprintf()`` function fails.
 */
std::string real128::to_string() const
{
    std::ostringstream oss;
    detail::float128_stream(oss, m_value);
    return oss.str();
}

/// Sign bit.
/**
 * This method will return the value of the sign bit of \p this. That is, if \p this
 * is not a NaN the method will return \p true if \p this is negative, \p false otherwise.
 * If \p this is NaN, the sign bit of the NaN value will be returned.
 *
 * @return \p true if the sign bit of \p this is set, \p false otherwise.
 */
bool real128::signbit() const
{
    return ::signbitq(m_value);
}

/// In-place square root.
/**
 * This method will set \p this to its nonnegative square root.
 * If \p this is less than negative zero, the result will be NaN.
 *
 * @return a reference to \p this.
 */
real128 &real128::sqrt()
{
    return *this = ::sqrtq(m_value);
}

/// In-place cube root.
/**
 * This method will set \p this to its real cube root.
 *
 * @return a reference to \p this.
 */
real128 &real128::cbrt()
{
    return *this = ::cbrtq(m_value);
}

/// In-place sine.
/**
 * This method will set \p this to its sine.
 *
 * @return a reference to \p this.
 */
real128 &real128::sin()
{
    return *this = ::sinq(m_value);
}

/// In-place cosine.
/**
 * This method will set \p this to its cosine.
 *
 * @return a reference to \p this.
 */
real128 &real128::cos()
{
    return *this = ::cosq(m_value);
}

/// In-place tangent.
/**
 * This method will set \p this to its trigonometric tangent.
 *
 * @return a reference to \p this.
 */
real128 &real128::tan()
{
    return *this = ::tanq(m_value);
}

/// In-place inverse sine.
/**
 * This method will set \p this to its inverse sine.
 *
 * @return a reference to \p this.
 */
real128 &real128::asin()
{
    return *this = ::asinq(m_value);
}

/// In-place inverse cosine.
/**
 * This method will set \p this to its inverse cosine.
 *
 * @return a reference to \p this.
 */
real128 &real128::acos()
{
    return *this = ::acosq(m_value);
}

/// In-place inverse tangent.
/**
 * This method will set \p this to its inverse trigonomotric tangent.
 *
 * @return a reference to \p this.
 */
real128 &real128::atan()
{
    return *this = ::atanq(m_value);
}

/// In-place hyperbolic sine.
/**
 * This method will set \p this to its hyperbolic sine.
 *
 * @return a reference to \p this.
 */
real128 &real128::sinh()
{
    return *this = ::sinhq(m_value);
}

/// In-place hyperbolic cosine.
/**
 * This method will set \p this to its hyperbolic cosine.
 *
 * @return a reference to \p this.
 */
real128 &real128::cosh()
{
    return *this = ::coshq(m_value);
}

/// In-place hyperbolic tangent.
/**
 * This method will set \p this to its hyperbolic tangent.
 *
 * @return a reference to \p this.
 */
real128 &real128::tanh()
{
    return *this = ::tanhq(m_value);
}

/// In-place inverse hyperbolic sine.
/**
 * This method will set \p this to its inverse hyperbolic sine.
 *
 * @return a reference to \p this.
 */
real128 &real128::asinh()
{
    return *this = ::asinhq(m_value);
}

/// In-place inverse hyperbolic cosine.
/**
 * This method will set \p this to its inverse hyperbolic cosine.
 *
 * @return a reference to \p this.
 */
real128 &real128::acosh()
{
    return *this = ::acoshq(m_value);
}

/// In-place inverse hyperbolic tangent.
/**
 * This method will set \p this to its inverse hyperbolic tangent.
 *
 * @return a reference to \p this.
 */
real128 &real128::atanh()
{
    return *this = ::atanhq(m_value);
}

/// In-place natural exponential function.
/**
 * This method will set \p this to \f$ \mathrm{e} \f$ raised to the power of \p this.
 *
 * @return a reference to \p this.
 */
real128 &real128::exp()
{
    return *this = ::expq(m_value);
}

/// In-place natural logarithm.
/**
 * This method will set \p this to its natural logarithm.
 *
 * @return a reference to \p this.
 */
real128 &real128::log()
{
    return *this = ::logq(m_value);
}

/// In-place base-10 logarithm.
/**
 * This method will set \p this to its base-10 logarithm.
 *
 * @return a reference to \p this.
 */
real128 &real128::log10()
{
    return *this = ::log10q(m_value);
}

/// In-place base-2 logarithm.
/**
 * This method will set \p this to its base-2 logarithm.
 *
 * @return a reference to \p this.
 */
real128 &real128::log2()
{
    return *this = ::log2q(m_value);
}

/// In-place lgamma function.
/**
 * This method will set \p this to the value of the natural logarithm of its gamma function.
 *
 * @return a reference to \p this.
 */
real128 &real128::lgamma()
{
    return *this = ::lgammaq(m_value);
}

/// In-place error function.
/**
 * This method will set \p this to the value of its error function.
 *
 * @return a reference to \p this.
 */
real128 &real128::erf()
{
    return *this = ::erfq(m_value);
}

/// Decompose a \link mppp::real128 real128\endlink into a normalized fraction and an integral power of two.
/**
 * \rststar
 * If ``x`` is zero, this function will return zero and store zero in ``exp``. Otherwise,
 * this function will return a :cpp:class:`~mppp::real128` :math:`r` with an absolute value in the
 * :math:`\left[0.5,1\right)` range, and it will store an integer value :math:`n` in ``exp``
 * such that :math:`r \times 2^n` equals to :math:`r`. If ``x`` is a non-finite value, the return
 * value will be ``x`` and an unspecified value will be stored in ``exp``.
 * \endrststar
 *
 * @param x the input \link mppp::real128 real128\endlink.
 * @param exp a pointer to the value that will store the exponent.
 *
 * @return the binary significand of ``x``.
 */
real128 frexp(const real128 &x, int *exp)
{
    return real128{::frexpq(x.m_value, exp)};
}

/// Fused multiply-add.
/**
 * \rststar
 * This function will return :math:`\left(x \times y\right) + z` as if calculated to infinite precision and
 * rounded once.
 * \endrststar
 *
 * @param x the first factor.
 * @param y the second factor.
 * @param z the addend.
 *
 * @return \f$ \left(x \times y\right) + z \f$.
 */
real128 fma(const real128 &x, const real128 &y, const real128 &z)
{
    return real128{::fmaq(x.m_value, y.m_value, z.m_value)};
}

/// Euclidean distance.
/**
 * The calculation is performed without undue overflow or underflow during the intermediate
 * steps of the calculation.
 *
 * @param x the first \link mppp::real128 real128\endlink argument.
 * @param y the second \link mppp::real128 real128\endlink argument.
 *
 * @return the euclidean distance \f$ \sqrt{x^2+y^2} \f$.
 */
real128 hypot(const real128 &x, const real128 &y)
{
    return real128{::hypotq(x.m_value, y.m_value)};
}

// Next real128 from 'from' to 'to'.
real128 nextafter(const real128 &from, const real128 &to)
{
    return real128{::nextafterq(from.m_value, to.m_value)};
}

} // namespace mppp
<commit_msg>Minor internal doc fix.<commit_after>// Copyright 2016-2020 Francesco Biscani (bluescarni@gmail.com)
//
// This file is part of the mp++ library.
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.

#include <ostream>
#include <sstream>
#include <stdexcept>
#include <string>

// NOTE: extern "C" is already included in quadmath.h since GCC 4.8:
// https://stackoverflow.com/questions/13780219/link-libquadmath-with-c-on-linux
#include <quadmath.h>

#include <mp++/config.hpp>
#include <mp++/detail/utils.hpp>
#include <mp++/real128.hpp>

namespace mppp
{

// Double check our assumption regarding
// the number of binary digits in the
// significand.
static_assert(FLT128_MANT_DIG == real128_sig_digits(), "Invalid number of digits.");

namespace detail
{

void float128_stream(std::ostream &os, const __float128 &x)
{
    char buf[100];
    // NOTE: 36 decimal digits ensure that reading back the string always produces the same value:
    // https://en.wikipedia.org/wiki/Quadruple-precision_floating-point_format
    // NOTE: when using the g/G format, the precision field represents the number
    // of significant digits:
    // https://linux.die.net/man/3/printf
    const auto n = ::quadmath_snprintf(buf, sizeof(buf), "%.36Qg", x);
    // LCOV_EXCL_START
    if (mppp_unlikely(n < 0)) {
        throw std::runtime_error("A call to quadmath_snprintf() failed: a negative exit status of " + to_string(n)
                                 + " was returned");
    }
    if (mppp_unlikely(unsigned(n) >= sizeof(buf))) {
        throw std::runtime_error("A call to quadmath_snprintf() failed: the exit status " + to_string(n)
                                 + " is not less than the size of the internal buffer " + to_string(sizeof(buf)));
    }
    // LCOV_EXCL_STOP
    os << &buf[0];
}

__float128 str_to_float128(const char *s)
{
    char *endptr;
    auto retval = ::strtoflt128(s, &endptr);
    if (mppp_unlikely(endptr == s || *endptr != '\0')) {
        // NOTE: the first condition handles an empty string.
        // endptr will point to the first character in the string which
        // did not contribute to the construction of retval.
        throw std::invalid_argument("The string '" + std::string(s)
                                    + "' does not represent a valid quadruple-precision floating-point value");
    }
    return retval;
}

__float128 scalbnq(__float128 x, int exp)
{
    return ::scalbnq(x, exp);
}

__float128 scalblnq(__float128 x, long exp)
{
    return ::scalblnq(x, exp);
}

__float128 powq(__float128 x, __float128 y)
{
    return ::powq(x, y);
}

} // namespace detail

/// Constructor from range of characters.
/**
 * This constructor will initialise \p this from the content of the input half-open range, which is interpreted
 * as the string representation of a floating-point value.
 *
 * Internally, the constructor will copy the content of the range to a local buffer, add a string terminator, and
 * invoke the constructor from string.
 *
 * @param begin the begin of the input range.
 * @param end the end of the input range.
 *
 * @throws unspecified any exception thrown by the constructor from string or by memory errors in standard
 * containers.
 */
real128::real128(const char *begin, const char *end)
{
    MPPP_MAYBE_TLS std::vector<char> buffer;
    buffer.assign(begin, end);
    buffer.emplace_back('\0');
    m_value = detail::str_to_float128(buffer.data());
}

/// Convert to string.
/**
 * \rststar
 * This method will convert ``this`` to a decimal string representation in scientific format.
 * The number of significant digits in the output (36) guarantees that a :cpp:class:`~mppp::real128`
 * constructed from the returned string will have a value identical to the value of ``this``.
 *
 * The implementation uses the ``quadmath_snprintf()`` function from the quadmath library.
 *
 * .. seealso::
 *    https://gcc.gnu.org/onlinedocs/libquadmath/quadmath_005fsnprintf.html
 * \endrststar
 *
 * @return a decimal string representation of ``this``.
 *
 * @throws std::runtime_error if the internal call to the ``quadmath_snprintf()`` function fails.
 */
std::string real128::to_string() const
{
    std::ostringstream oss;
    detail::float128_stream(oss, m_value);
    return oss.str();
}

/// Sign bit.
/**
 * This method will return the value of the sign bit of \p this. That is, if \p this
 * is not a NaN the method will return \p true if \p this is negative, \p false otherwise.
 * If \p this is NaN, the sign bit of the NaN value will be returned.
 *
 * @return \p true if the sign bit of \p this is set, \p false otherwise.
 */
bool real128::signbit() const
{
    return ::signbitq(m_value);
}

/// In-place square root.
/**
 * This method will set \p this to its nonnegative square root.
 * If \p this is less than negative zero, the result will be NaN.
 *
 * @return a reference to \p this.
 */
real128 &real128::sqrt()
{
    return *this = ::sqrtq(m_value);
}

/// In-place cube root.
/**
 * This method will set \p this to its real cube root.
 *
 * @return a reference to \p this.
 */
real128 &real128::cbrt()
{
    return *this = ::cbrtq(m_value);
}

/// In-place sine.
/**
 * This method will set \p this to its sine.
 *
 * @return a reference to \p this.
 */
real128 &real128::sin()
{
    return *this = ::sinq(m_value);
}

/// In-place cosine.
/**
 * This method will set \p this to its cosine.
 *
 * @return a reference to \p this.
 */
real128 &real128::cos()
{
    return *this = ::cosq(m_value);
}

/// In-place tangent.
/**
 * This method will set \p this to its trigonometric tangent.
 *
 * @return a reference to \p this.
 */
real128 &real128::tan()
{
    return *this = ::tanq(m_value);
}

/// In-place inverse sine.
/**
 * This method will set \p this to its inverse sine.
 *
 * @return a reference to \p this.
 */
real128 &real128::asin()
{
    return *this = ::asinq(m_value);
}

/// In-place inverse cosine.
/**
 * This method will set \p this to its inverse cosine.
 *
 * @return a reference to \p this.
 */
real128 &real128::acos()
{
    return *this = ::acosq(m_value);
}

/// In-place inverse tangent.
/**
 * This method will set \p this to its inverse trigonomotric tangent.
 *
 * @return a reference to \p this.
 */
real128 &real128::atan()
{
    return *this = ::atanq(m_value);
}

/// In-place hyperbolic sine.
/**
 * This method will set \p this to its hyperbolic sine.
 *
 * @return a reference to \p this.
 */
real128 &real128::sinh()
{
    return *this = ::sinhq(m_value);
}

/// In-place hyperbolic cosine.
/**
 * This method will set \p this to its hyperbolic cosine.
 *
 * @return a reference to \p this.
 */
real128 &real128::cosh()
{
    return *this = ::coshq(m_value);
}

/// In-place hyperbolic tangent.
/**
 * This method will set \p this to its hyperbolic tangent.
 *
 * @return a reference to \p this.
 */
real128 &real128::tanh()
{
    return *this = ::tanhq(m_value);
}

/// In-place inverse hyperbolic sine.
/**
 * This method will set \p this to its inverse hyperbolic sine.
 *
 * @return a reference to \p this.
 */
real128 &real128::asinh()
{
    return *this = ::asinhq(m_value);
}

/// In-place inverse hyperbolic cosine.
/**
 * This method will set \p this to its inverse hyperbolic cosine.
 *
 * @return a reference to \p this.
 */
real128 &real128::acosh()
{
    return *this = ::acoshq(m_value);
}

/// In-place inverse hyperbolic tangent.
/**
 * This method will set \p this to its inverse hyperbolic tangent.
 *
 * @return a reference to \p this.
 */
real128 &real128::atanh()
{
    return *this = ::atanhq(m_value);
}

/// In-place natural exponential function.
/**
 * This method will set \p this to \f$ \mathrm{e} \f$ raised to the power of \p this.
 *
 * @return a reference to \p this.
 */
real128 &real128::exp()
{
    return *this = ::expq(m_value);
}

/// In-place natural logarithm.
/**
 * This method will set \p this to its natural logarithm.
 *
 * @return a reference to \p this.
 */
real128 &real128::log()
{
    return *this = ::logq(m_value);
}

/// In-place base-10 logarithm.
/**
 * This method will set \p this to its base-10 logarithm.
 *
 * @return a reference to \p this.
 */
real128 &real128::log10()
{
    return *this = ::log10q(m_value);
}

/// In-place base-2 logarithm.
/**
 * This method will set \p this to its base-2 logarithm.
 *
 * @return a reference to \p this.
 */
real128 &real128::log2()
{
    return *this = ::log2q(m_value);
}

/// In-place lgamma function.
/**
 * This method will set \p this to the value of the natural logarithm of its gamma function.
 *
 * @return a reference to \p this.
 */
real128 &real128::lgamma()
{
    return *this = ::lgammaq(m_value);
}

/// In-place error function.
/**
 * This method will set \p this to the value of its error function.
 *
 * @return a reference to \p this.
 */
real128 &real128::erf()
{
    return *this = ::erfq(m_value);
}

/// Decompose a \link mppp::real128 real128\endlink into a normalized fraction and an integral power of two.
/**
 * \rststar
 * If ``x`` is zero, this function will return zero and store zero in ``exp``. Otherwise,
 * this function will return a :cpp:class:`~mppp::real128` :math:`r` with an absolute value in the
 * :math:`\left[0.5,1\right)` range, and it will store an integer value :math:`n` in ``exp``
 * such that :math:`r \times 2^n` equals to :math:`r`. If ``x`` is a non-finite value, the return
 * value will be ``x`` and an unspecified value will be stored in ``exp``.
 * \endrststar
 *
 * @param x the input \link mppp::real128 real128\endlink.
 * @param exp a pointer to the value that will store the exponent.
 *
 * @return the binary significand of ``x``.
 */
real128 frexp(const real128 &x, int *exp)
{
    return real128{::frexpq(x.m_value, exp)};
}

/// Fused multiply-add.
/**
 * \rststar
 * This function will return :math:`\left(x \times y\right) + z` as if calculated to infinite precision and
 * rounded once.
 * \endrststar
 *
 * @param x the first factor.
 * @param y the second factor.
 * @param z the addend.
 *
 * @return \f$ \left(x \times y\right) + z \f$.
 */
real128 fma(const real128 &x, const real128 &y, const real128 &z)
{
    return real128{::fmaq(x.m_value, y.m_value, z.m_value)};
}

/// Euclidean distance.
/**
 * The calculation is performed without undue overflow or underflow during the intermediate
 * steps of the calculation.
 *
 * @param x the first \link mppp::real128 real128\endlink argument.
 * @param y the second \link mppp::real128 real128\endlink argument.
 *
 * @return the euclidean distance \f$ \sqrt{x^2+y^2} \f$.
 */
real128 hypot(const real128 &x, const real128 &y)
{
    return real128{::hypotq(x.m_value, y.m_value)};
}

// Next real128 from 'from' to 'to'.
real128 nextafter(const real128 &from, const real128 &to)
{
    return real128{::nextafterq(from.m_value, to.m_value)};
}

} // namespace mppp
<|endoftext|>


<commit_before>#include	<cstdlib>
#include	<cmath>
#include	<fstream>
#include	<sstream>
#include	<iostream>
#include	<iomanip>
#include	<string>
#include	<vector>
#include	<algorithm>
#include	<exception>
#include	<sys/time.h>
#include	"modules/htmTree.h"
#include	"modules/kdTree.h"
#include        "misc.h"
#include        "feat.h"
#include        "structs.h"
#include        "collision.h"
#include        "global.h"
//reduce redistributes, updates  07/02/15 rnc
int main(int argc, char **argv) {
	//// Initializations ---------------------------------------------
	srand48(1234); // Make sure we have reproducability
	check_args(argc);
	Time t, time; // t for global, time for local
	init_time(t);
	Feat F;

	// Read parameters file //
	F.readInputFile(argv[1]);
	printFile(argv[1]);

	// Read galaxies
	Gals G;
    if(F.Ascii){
        G=read_galaxies_ascii(F);}
    else{
        G = read_galaxies(F);
    }
	F.Ngal = G.size();
	printf("# Read %s galaxies from %s \n",f(F.Ngal).c_str(),F.galFile.c_str());

	// Read fiber center positions and compute related things
	PP pp;
	pp.read_fiber_positions(F);
	F.Nfiber = pp.fp.size()/2;
	F.Npetal = max(pp.spectrom)+1; // spectrometer has to be identified from 0 to F.Npetal-1
	F.Nfbp = (int) (F.Nfiber/F.Npetal);// fibers per petal = 500
	pp.get_neighbors(F); pp.compute_fibsofsp(F);//get neighbors of each fiber;
                                                //for each spectrometer, get list of fibers

	// Read plates in order they are to be observed

	Plates P = read_plate_centers(F);
	F.Nplate = P.size();
	printf("# Read %s plate centers from %s and %d fibers from %s\n",f(F.Nplate).c_str(),F.tileFile.c_str(),F.Nfiber,F.fibFile.c_str());

	// Computes geometries of cb and fh: pieces of positioner - used to determine possible collisions
	F.cb = create_cb(); // cb=central body
	F.fh = create_fh(); // fh=fiber holder

	//// Collect available galaxies <-> tilefibers --------------------
	// HTM Tree of galaxies
	const double MinTreeSize = 0.01;
	init_time_at(time,"# Start building HTM tree",t);
	htmTree<struct galaxy> T(G,MinTreeSize);
	print_time(time,"# ... took :");//T.stats();

	// For plates/fibers, collect available galaxies; done in parallel  P[plate j].av_gal[k]=[g1,g2,..]
	collect_galaxies_for_all(G,T,P,pp,F);

	// For each galaxy, computes available tilefibers  G[i].av_tfs = [(j1,k1),(j2,k2),..]
	collect_available_tilefibers(G,P,F);

	//results_on_inputs("doc/figs/",G,P,F,true);

	//// Assignment |||||||||||||||||||||||||||||||||||||||||||||||||||
    printf("before assignment\n");
	Assignment A(G,F);
	print_time(t,"# Start assignment at : ");

	// Make a plan ----------------------------------------------------
	//new_assign_fibers(G,P,pp,F,A); // Plans whole survey without sky fibers, standard stars
                                   // assumes maximum number of observations needed for QSOs, LRGs
    printf(" Nplate %d  Ngal %d   Nfiber %d \n", F.Nplate, F.Ngal, F.Nfiber);
    //simple_assign(G,P,pp,F,A);

    /*
	print_hist("Unused fibers",5,histogram(A.unused_fbp(pp,F),5),false); // Hist of unused fibs
                                    // Want to have even distribution of unused fibers
                                    // so we can put in sky fibers and standard stars

	// Smooth out distribution of free fibers, and increase the number of assignments
	for (int i=0; i<1; i++) redistribute_tf(G,P,pp,F,A);// more iterations will improve performance slightly
	for (int i=0; i<1; i++) {                           // more iterations will improve performance slightly
		improve(G,P,pp,F,A);
		redistribute_tf(G,P,pp,F,A);
		redistribute_tf(G,P,pp,F,A);
	}
	for (int i=0; i<1; i++) redistribute_tf(G,P,pp,F,A);

	print_hist("Unused fibers",5,histogram(A.unused_fbp(pp,F),5),false);

	// Still not updated, so all QSO targets have multiple observations etc
	// Apply and update the plan --------------------------------------
	init_time_at(time,"# Begin real time assignment",t);
	for (int jj=0; jj<F.Nplate; jj++) {
		int j = A.next_plate;
		//printf(" - Plate %d :",j);
		assign_sf_ss(j,G,P,pp,F,A); // Assign SS and SF just before an observation
		assign_unused(j,G,P,pp,F,A);
		//if (j%2000==0) pyplotTile(j,"doc/figs",G,P,pp,F,A); // Picture of positioners, galaxies

		//printf(" %s not as - ",format(5,f(A.unused_f(j,F))).c_str()); fl();
		// Update corrects all future occurrences of wrong QSOs etc and tries to observe something else
		if (0<=j-F.Analysis) update_plan_from_one_obs(G,P,pp,F,A,F.Nplate-1); else printf("\n");
		A.next_plate++;
		// Redistribute and improve on various occasions  add more times if desired

		if ( j==2000 || j==4000) {
			redistribute_tf(G,P,pp,F,A);
			redistribute_tf(G,P,pp,F,A);
			improve(G,P,pp,F,A);
			redistribute_tf(G,P,pp,F,A);
		}
	}
	print_time(time,"# ... took :");

	// Results -------------------------------------------------------
	if (F.Output) for (int j=0; j<F.Nplate; j++) write_FAtile_ascii(j,F.outDir,G,P,pp,F,A); // Write output
	display_results("doc/figs/",G,P,pp,F,A,true);
	if (F.Verif) A.verif(P,G,pp,F); // Verification that the assignment is sane

	print_time(t,"# Finished !... in");
     */
	return(0);
}
<commit_msg>restore simple_assign<commit_after>#include	<cstdlib>
#include	<cmath>
#include	<fstream>
#include	<sstream>
#include	<iostream>
#include	<iomanip>
#include	<string>
#include	<vector>
#include	<algorithm>
#include	<exception>
#include	<sys/time.h>
#include	"modules/htmTree.h"
#include	"modules/kdTree.h"
#include        "misc.h"
#include        "feat.h"
#include        "structs.h"
#include        "collision.h"
#include        "global.h"
//reduce redistributes, updates  07/02/15 rnc
int main(int argc, char **argv) {
	//// Initializations ---------------------------------------------
	srand48(1234); // Make sure we have reproducability
	check_args(argc);
	Time t, time; // t for global, time for local
	init_time(t);
	Feat F;

	// Read parameters file //
	F.readInputFile(argv[1]);
	printFile(argv[1]);

	// Read galaxies
	Gals G;
    if(F.Ascii){
        G=read_galaxies_ascii(F);}
    else{
        G = read_galaxies(F);
    }
	F.Ngal = G.size();
	printf("# Read %s galaxies from %s \n",f(F.Ngal).c_str(),F.galFile.c_str());

	// Read fiber center positions and compute related things
	PP pp;
	pp.read_fiber_positions(F);
	F.Nfiber = pp.fp.size()/2;
	F.Npetal = max(pp.spectrom)+1; // spectrometer has to be identified from 0 to F.Npetal-1
	F.Nfbp = (int) (F.Nfiber/F.Npetal);// fibers per petal = 500
	pp.get_neighbors(F); pp.compute_fibsofsp(F);//get neighbors of each fiber;
                                                //for each spectrometer, get list of fibers

	// Read plates in order they are to be observed

	Plates P = read_plate_centers(F);
	F.Nplate = P.size();
	printf("# Read %s plate centers from %s and %d fibers from %s\n",f(F.Nplate).c_str(),F.tileFile.c_str(),F.Nfiber,F.fibFile.c_str());

	// Computes geometries of cb and fh: pieces of positioner - used to determine possible collisions
	F.cb = create_cb(); // cb=central body
	F.fh = create_fh(); // fh=fiber holder

	//// Collect available galaxies <-> tilefibers --------------------
	// HTM Tree of galaxies
	const double MinTreeSize = 0.01;
	init_time_at(time,"# Start building HTM tree",t);
	htmTree<struct galaxy> T(G,MinTreeSize);
	print_time(time,"# ... took :");//T.stats();

	// For plates/fibers, collect available galaxies; done in parallel  P[plate j].av_gal[k]=[g1,g2,..]
	collect_galaxies_for_all(G,T,P,pp,F);

	// For each galaxy, computes available tilefibers  G[i].av_tfs = [(j1,k1),(j2,k2),..]
	collect_available_tilefibers(G,P,F);

	//results_on_inputs("doc/figs/",G,P,F,true);

	//// Assignment |||||||||||||||||||||||||||||||||||||||||||||||||||
    printf("before assignment\n");
	Assignment A(G,F);
	print_time(t,"# Start assignment at : ");

	// Make a plan ----------------------------------------------------
	//new_assign_fibers(G,P,pp,F,A); // Plans whole survey without sky fibers, standard stars
                                   // assumes maximum number of observations needed for QSOs, LRGs
    printf(" Nplate %d  Ngal %d   Nfiber %d \n", F.Nplate, F.Ngal, F.Nfiber);
    simple_assign(G,P,pp,F,A);

    /*
	print_hist("Unused fibers",5,histogram(A.unused_fbp(pp,F),5),false); // Hist of unused fibs
                                    // Want to have even distribution of unused fibers
                                    // so we can put in sky fibers and standard stars

	// Smooth out distribution of free fibers, and increase the number of assignments
	for (int i=0; i<1; i++) redistribute_tf(G,P,pp,F,A);// more iterations will improve performance slightly
	for (int i=0; i<1; i++) {                           // more iterations will improve performance slightly
		improve(G,P,pp,F,A);
		redistribute_tf(G,P,pp,F,A);
		redistribute_tf(G,P,pp,F,A);
	}
	for (int i=0; i<1; i++) redistribute_tf(G,P,pp,F,A);

	print_hist("Unused fibers",5,histogram(A.unused_fbp(pp,F),5),false);

	// Still not updated, so all QSO targets have multiple observations etc
	// Apply and update the plan --------------------------------------
	init_time_at(time,"# Begin real time assignment",t);
	for (int jj=0; jj<F.Nplate; jj++) {
		int j = A.next_plate;
		//printf(" - Plate %d :",j);
		assign_sf_ss(j,G,P,pp,F,A); // Assign SS and SF just before an observation
		assign_unused(j,G,P,pp,F,A);
		//if (j%2000==0) pyplotTile(j,"doc/figs",G,P,pp,F,A); // Picture of positioners, galaxies

		//printf(" %s not as - ",format(5,f(A.unused_f(j,F))).c_str()); fl();
		// Update corrects all future occurrences of wrong QSOs etc and tries to observe something else
		if (0<=j-F.Analysis) update_plan_from_one_obs(G,P,pp,F,A,F.Nplate-1); else printf("\n");
		A.next_plate++;
		// Redistribute and improve on various occasions  add more times if desired

		if ( j==2000 || j==4000) {
			redistribute_tf(G,P,pp,F,A);
			redistribute_tf(G,P,pp,F,A);
			improve(G,P,pp,F,A);
			redistribute_tf(G,P,pp,F,A);
		}
	}
	print_time(time,"# ... took :");

	// Results -------------------------------------------------------
	if (F.Output) for (int j=0; j<F.Nplate; j++) write_FAtile_ascii(j,F.outDir,G,P,pp,F,A); // Write output
	display_results("doc/figs/",G,P,pp,F,A,true);
	if (F.Verif) A.verif(P,G,pp,F); // Verification that the assignment is sane

	print_time(t,"# Finished !... in");
     */
	return(0);
}
<|endoftext|>


<commit_before>#include <new>

#include <string.h>

#include "nju9103.h"

static uint8_t rx_buffer[PACKET_SIZE];
static ReceiveDataStatus receiveDataStatus;
static Command command;

static ::Serial *uart;
static ::Timer *packetWatchTimer;
static ::Dispatcher *dispatcher;
static ::ADCDataBuffer *adcDataBuffer;

void setup() {
    receiveDataStatus = 0;
    command = 0;

    uart = new ::Serial(UART_BAUDRATE, UART_BITS, UART_PARITY, UART_STOP);
    packetWatchTimer = new ::Timer();
    dispatcher = new ::Dispatcher();
    adcDataBuffer = new ::ADCDataBuffer;

    // set Rx interrupt
    uart->attach(isrRx, ::Serial::RxIrq);
    packetWatchTimer->attach(isrPacketWatch, 300);
}

void loop() {
    Packet packet;

    if (command != 0) {
        ::Dispatcher::Status status;
        status = dispatcher->Dispatch(&command, rx_buffer, &packet, adcDataBuffer);

        if (status != ::Dispatcher::Abort) {
            sendPacket(&packet);
            if (packet.Type == OP_START_ADC_DATA_DUMP) {
                adcDataBuffer->Dump(sendPacket);
            }
        }
    }
}

NJRC_STATIC void isrRx() {
    static char buf[PACKET_SIZE];
    static uint8_t count = 0;
    while (uart->readable()) {
        if (count < sizeof(buf)) {
            buf[count] = uart->read();
        }
        else if (count == sizeof(buf)) {
            receiveDataStatus = RX_STATUS_DATA_RECEIVED;
            if (uart->read() == calculateChkSum((uint8_t*)buf)) {
                memcpy(rx_buffer, buf, sizeof(uint8_t) * PACKET_SIZE);
            }
            else {
                receiveDataStatus |= RX_STATUS_CHKSUM_ERROR;
            }
        }
        count = (count + 1) % (sizeof(buf) + 1);
    }
}

NJRC_STATIC void isrPacketWatch() {
    if (receiveDataStatus & RX_STATUS_DATA_RECEIVED) {
        receiveDataStatus ^= RX_STATUS_DATA_RECEIVED;
        if ((receiveDataStatus & RX_STATUS_CHKSUM_ERROR) == 0) {
            decodeCommand(rx_buffer[0], rx_buffer[1], &command);
            if ((command & CMD_RESET) != 0) {
                if ((command & CMD_START_SINGLE) != 0) {
                    dispatcher->SetAbortRequest();
                }
                if ((command & CMD_START_CONTINUOUS) != 0) {
                    dispatcher->SetAbortRequest();
                }
                if ((command & CMD_START_DUMP) != 0) {
                    adcDataBuffer->SetAbortRequest();
                }
            }
            else if ((command & CMD_STOP_SINGLE) != 0) {
                if ((command & CMD_START_SINGLE) != 0) {
                    dispatcher->SetAbortRequest();
                }
            }
            else if ((command & CMD_STOP_CONTINUOUS) != 0) {
                if ((command & CMD_START_CONTINUOUS) != 0) {
                    dispatcher->SetAbortRequest();
                }
            }
            else if ((command & CMD_STOP_DUMP) != 0) {
                if ((command & CMD_START_DUMP) != 0) {
                    adcDataBuffer->SetAbortRequest();
                }
            }
        }
        else {
            receiveDataStatus ^= RX_STATUS_CHKSUM_ERROR;

            Packet packet;
            memset(&packet, 0, sizeof(Packet));
            packet.Header = ErrorHeader;
            packet.Type = OP_CHKSUM_ERROR;
            sendPacket(&packet);
        }
    }
}

NJRC_STATIC uint8_t calculateChkSum(Packet *packet) {
    uint8_t chksum = 0;
    chksum = (chksum + packet->Header) & 0xFF;
    chksum = (chksum + packet->Byte0) & 0xFF;
    chksum = (chksum + packet->Byte1) & 0xFF;
    chksum = (chksum + packet->Byte2) & 0xFF;
    chksum = (chksum + packet->Byte3) & 0xFF;
    chksum = (chksum + packet->Byte4) & 0xFF;
    chksum = (chksum + packet->Byte5) & 0xFF;
    chksum = (chksum + packet->Byte6) & 0xFF;
    chksum = (chksum + packet->Byte7) & 0xFF;
    return ~chksum;
}

NJRC_STATIC uint8_t calculateChkSum(uint8_t *data) {
    uint8_t chksum = 0;
    for (int i = 0; i < PACKET_SIZE; i++) {
        chksum = (chksum + *data++) & 0xFF;
    }
    return ~chksum;
}

NJRC_STATIC void sendPacket(Packet *packet) {
    uart->write(packet->Header);
    uart->write(packet->Byte0);
    uart->write(packet->Byte1);
    uart->write(packet->Byte2);
    uart->write(packet->Byte3);
    uart->write(packet->Byte4);
    uart->write(packet->Byte5);
    uart->write(packet->Byte6);
    uart->write(packet->Byte7);
    uart->write(calculateChkSum(packet));
}

NJRC_STATIC void decodeCommand(uint8_t header, uint8_t opcode, Command *cmd) {
    if (header == CommandHeader) {
        switch (opcode) {
            case OP_SPI_RESET :
                *cmd |= CMD_RESET;
                break;
            case OP_REGISTER_WRITE_8BIT :
                *cmd |= CMD_WRITE_8BIT;
                break;
            case OP_REGISTER_READ_8BIT :
                *cmd |= CMD_READ_8BIT;
                break;
            case OP_REGISTER_WRITE_16BIT :
                *cmd |= CMD_WRITE_16BIT;
                break;
            case OP_REGISTER_READ_16BIT :
                *cmd |= CMD_READ_16BIT;
                break;
            case OP_START_SINGLE_CONVERSION :
                *cmd |= CMD_START_SINGLE;
                break;
            case OP_START_CONTINUOUS_CONVERSION :
                *cmd |= CMD_START_CONTINUOUS;
                break;
            case OP_START_ADC_DATA_DUMP :
                *cmd |= CMD_START_DUMP;
                break;
            case OP_STOP_SINGLE_CONVERSION :
                *cmd |= CMD_STOP_SINGLE;
                break;
            case OP_STOP_CONTINUOUS_CONVERSION :
                *cmd |= CMD_STOP_CONTINUOUS;
                break;
            case OP_STOP_ADC_DATA_DUMP :
                *cmd |= CMD_STOP_DUMP;
                break;
            default :
                *cmd |= CMD_UNKNOWN;
                break;
        }
    }
    else {
        *cmd |= CMD_UNKNOWN;
    }
}
<commit_msg>Modify peripherals instance to without new<commit_after>#include <string.h>

#include "nju9103.h"

static uint8_t rx_buffer[PACKET_SIZE];
static ReceiveDataStatus receiveDataStatus;
static Command command;

static ::Serial uart(UART_BAUDRATE, UART_BITS, UART_PARITY, UART_STOP);
static ::Timer packetWatchTimer;
static ::Dispatcher dispatcher;
static ::ADCDataBuffer adcDataBuffer;

void setup() {
    receiveDataStatus = 0;
    command = 0;

    // set Rx interrupt
    uart.attach(isrRx, ::Serial::RxIrq);
    packetWatchTimer.attach(isrPacketWatch, 300);
}

void loop() {
    Packet packet;

    if (command != 0) {
        ::Dispatcher::Status status;
        status = dispatcher.Dispatch(&command, rx_buffer, &packet, &adcDataBuffer);

        if (status != ::Dispatcher::Abort) {
            sendPacket(&packet);
            if (packet.Type == OP_START_ADC_DATA_DUMP) {
                adcDataBuffer.Dump(sendPacket);
            }
        }
    }
}

NJRC_STATIC void isrRx() {
    static char buf[PACKET_SIZE];
    static uint8_t count = 0;
    while (uart.readable()) {
        if (count < sizeof(buf)) {
            buf[count] = uart.read();
        }
        else if (count == sizeof(buf)) {
            receiveDataStatus = RX_STATUS_DATA_RECEIVED;
            if (uart.read() == calculateChkSum((uint8_t*)buf)) {
                memcpy(rx_buffer, buf, sizeof(uint8_t) * PACKET_SIZE);
            }
            else {
                receiveDataStatus |= RX_STATUS_CHKSUM_ERROR;
            }
        }
        count = (count + 1) % (sizeof(buf) + 1);
    }
}

NJRC_STATIC void isrPacketWatch() {
    if (receiveDataStatus & RX_STATUS_DATA_RECEIVED) {
        receiveDataStatus ^= RX_STATUS_DATA_RECEIVED;
        if ((receiveDataStatus & RX_STATUS_CHKSUM_ERROR) == 0) {
            decodeCommand(rx_buffer[0], rx_buffer[1], &command);
            if ((command & CMD_RESET) != 0) {
                if ((command & CMD_START_SINGLE) != 0) {
                    dispatcher.SetAbortRequest();
                }
                if ((command & CMD_START_CONTINUOUS) != 0) {
                    dispatcher.SetAbortRequest();
                }
                if ((command & CMD_START_DUMP) != 0) {
                    adcDataBuffer.SetAbortRequest();
                }
            }
            else if ((command & CMD_STOP_SINGLE) != 0) {
                if ((command & CMD_START_SINGLE) != 0) {
                    dispatcher.SetAbortRequest();
                }
            }
            else if ((command & CMD_STOP_CONTINUOUS) != 0) {
                if ((command & CMD_START_CONTINUOUS) != 0) {
                    dispatcher.SetAbortRequest();
                }
            }
            else if ((command & CMD_STOP_DUMP) != 0) {
                if ((command & CMD_START_DUMP) != 0) {
                    adcDataBuffer.SetAbortRequest();
                }
            }
        }
        else {
            receiveDataStatus ^= RX_STATUS_CHKSUM_ERROR;

            Packet packet;
            memset(&packet, 0, sizeof(Packet));
            packet.Header = ErrorHeader;
            packet.Type = OP_CHKSUM_ERROR;
            sendPacket(&packet);
        }
    }
}

NJRC_STATIC uint8_t calculateChkSum(Packet *packet) {
    uint8_t chksum = 0;
    chksum = (chksum + packet->Header) & 0xFF;
    chksum = (chksum + packet->Byte0) & 0xFF;
    chksum = (chksum + packet->Byte1) & 0xFF;
    chksum = (chksum + packet->Byte2) & 0xFF;
    chksum = (chksum + packet->Byte3) & 0xFF;
    chksum = (chksum + packet->Byte4) & 0xFF;
    chksum = (chksum + packet->Byte5) & 0xFF;
    chksum = (chksum + packet->Byte6) & 0xFF;
    chksum = (chksum + packet->Byte7) & 0xFF;
    return ~chksum;
}

NJRC_STATIC uint8_t calculateChkSum(uint8_t *data) {
    uint8_t chksum = 0;
    for (int i = 0; i < PACKET_SIZE; i++) {
        chksum = (chksum + *data++) & 0xFF;
    }
    return ~chksum;
}

NJRC_STATIC void sendPacket(Packet *packet) {
    uart.write(packet->Header);
    uart.write(packet->Byte0);
    uart.write(packet->Byte1);
    uart.write(packet->Byte2);
    uart.write(packet->Byte3);
    uart.write(packet->Byte4);
    uart.write(packet->Byte5);
    uart.write(packet->Byte6);
    uart.write(packet->Byte7);
    uart.write(calculateChkSum(packet));
}

NJRC_STATIC void decodeCommand(uint8_t header, uint8_t opcode, Command *cmd) {
    if (header == CommandHeader) {
        switch (opcode) {
            case OP_SPI_RESET :
                *cmd |= CMD_RESET;
                break;
            case OP_REGISTER_WRITE_8BIT :
                *cmd |= CMD_WRITE_8BIT;
                break;
            case OP_REGISTER_READ_8BIT :
                *cmd |= CMD_READ_8BIT;
                break;
            case OP_REGISTER_WRITE_16BIT :
                *cmd |= CMD_WRITE_16BIT;
                break;
            case OP_REGISTER_READ_16BIT :
                *cmd |= CMD_READ_16BIT;
                break;
            case OP_START_SINGLE_CONVERSION :
                *cmd |= CMD_START_SINGLE;
                break;
            case OP_START_CONTINUOUS_CONVERSION :
                *cmd |= CMD_START_CONTINUOUS;
                break;
            case OP_START_ADC_DATA_DUMP :
                *cmd |= CMD_START_DUMP;
                break;
            case OP_STOP_SINGLE_CONVERSION :
                *cmd |= CMD_STOP_SINGLE;
                break;
            case OP_STOP_CONTINUOUS_CONVERSION :
                *cmd |= CMD_STOP_CONTINUOUS;
                break;
            case OP_STOP_ADC_DATA_DUMP :
                *cmd |= CMD_STOP_DUMP;
                break;
            default :
                *cmd |= CMD_UNKNOWN;
                break;
        }
    }
    else {
        *cmd |= CMD_UNKNOWN;
    }
}
<|endoftext|>