Home Page
Open Source
Contact Us
Free Downloads
Releases and Credits
Software Status
License
About rrproj
assigning people and/or equipment to projects
High-Hope Technique
History of the AI
View Source Files
and how they are organized
Making Programs
Development Notes
Using aiParts
Your Application
Support and Services
|
|
aiParts Source File
//======================================================================
// rrproj_prob.cpp - function bodies for rrproj_prob.h
//
// Copyright (c) 2008 Brian Marshall
//
// See the license at end of this file.
//
// Developers/Contributers:
// [BRM] Brian Marshall - Calgary - bmarshal@agt.net
//
// 08/01/27 [BRM] began development
//
//----------------------------------------------------------------------
#include "rrproj_prob.h"
#include "rrproj_fctry.h"
#include <string.h>
#include <stdlib.h>
// #include // for debugging
// #include
// using namespace std;
//======================================================================
// local functions
//
//----------------------------------------------------------------------
// save the solution from a solver-problem in a problem-problem
void save_solution (rppProblem *rpp_problem, rpsProblem *rps_problem) {
rpsDecision * rd;
rpsOption * ro;
rpsPosDay * rpd;
rpsPosition * rp;
rpsEmployee * re;
long syyyymmdd;
aipHHOption * shhopt;
aipHHOptionItr oitr;
rpsDecisionItr ditr = rps_problem->decision_iterator();
for ( rd=ditr.first(); rd; rd=ditr.next() ) {
oitr = rd->bsf_opt_iterator();
for ( shhopt=oitr.first(); shhopt; shhopt=oitr.next() ) {
ro = (rpsOption*)shhopt;
rpd = ro->bsf_posday();
rp = rpd->pos();
re = ro->emp();
syyyymmdd = rpd->yyyymmdd();
rpp_problem->add_posdayemp ( rpd->proj_id(), rp->pos_id(),
syyyymmdd, re->emp_id() );
} // end of loop through options in best-so-far solution
} // end of loop through decisions
}
//======================================================================
// rppProblem
//
//----------------------------------------------------------------------
// Constructor
rppProblem::rppProblem () {
m_start_yyyymmdd = 19000101;
m_end_yyyymmdd = 19000101;
m_num_tries = 0;
m_logger = new aipStringLogger(Max_Log_Len);
if (m_logger) set_logger(m_logger);
m_posdays = new aipPandemonium;
m_empdows = new aipPandemonium;
m_empoffs = new aipPandemonium;
m_posemps = new aipPandemonium;
m_assignments = new aipPandemonium;
m_empdaypos = new aipPandemonium;
m_posdayemps = new aipPandemonium;
m_posdayemp_itr = 0; // managed by get_pos_day_emp()
}
//----------------------------------------------------------------------
// Destructor
rppProblem::~rppProblem () {
if (m_logger) delete m_logger;
if (m_posdays) delete m_posdays;
if (m_empdows) delete m_empdows;
if (m_empoffs) delete m_empoffs;
if (m_posemps) delete m_posemps;
if (m_assignments) delete m_assignments;
if (m_empdaypos) delete m_empdaypos;
if (m_posdayemps) delete m_posdayemps;
if (m_posdayemp_itr) delete m_posdayemp_itr;
}
//----------------------------------------------------------------------
// Return true if the problem is valid after construction.
// Log problems.
int rppProblem::is_valid () {
if ( ! m_posdays ) {
log("Error creating m_posdays");
return 0;
}
if ( ! m_empdows ) {
log("Error creating m_empdows");
return 0;
}
if ( ! m_empoffs ) {
log("Error creating m_empoffs");
return 0;
}
if ( ! m_posemps ) {
log("Error creating m_posemps");
return 0;
}
if ( ! m_assignments ) {
log("Error creating m_assignments");
return 0;
}
if ( ! m_empdaypos ) {
log("Error creating m_empdaypos");
return 0;
}
if ( ! m_posdayemps ) {
log("Error creating m_posdayemps");
return 0;
}
if (m_posdayemp_itr != 0) {
log("m_posdayemp_itr should be zero");
return 0;
}
return 1;
}
//----------------------------------------------------------------------
// Read the input data from a file; return 1 (true) on success
int rppProblem::read (const char *filename) {
FILE *ifp = fopen (filename, "r");
if (!ifp) {
log("Error opening input file: ");
log(filename);
return 0;
}
int istatus = 1;
int rstatus;
char buf[201], record_type[31];
const char *p;
while (istatus) {
rstatus = fgets(buf,200,ifp) != 0;
if (!rstatus) break;
buf[200] = '\0'; // make sure it is terminated
char *q = buf;
int anything = 0;
while (*q) { // terminate at the newline
if ( (*q >= 'A' && *q <= 'Z') ||
(*q >= 'a' && *q <= 'z') ||
(*q >= '0' && *q <= '9') ) {
anything = 1; // has some data
} else if (*q == '\n') {
*q = '\0';
break;
}
q++;
}
if (buf[0] == '#' || !anything) continue;
p = buf;
if (*p) p = aip_get_str(p, 30, record_type, '|');
if (!p) continue;
if ( strcmp (record_type, "rppProblem") == 0) {
istatus = read_str(p);
} else if ( strcmp (record_type, "rppPosDay") == 0) {
rppPosDay *pd = new rppPosDay;
if (!pd) { log("new pd failure"); return 0; }
istatus = pd->read_str(p);
if (istatus && m_posdays) {
m_posdays->add(pd);
} else {
delete pd;
}
} else if ( strcmp (record_type, "rppPosEmp") == 0) {
rppPosEmp *pqe = new rppPosEmp;
if (!pqe) { log("new pqe failure"); return 0; }
istatus = pqe->read_str(p);
if (istatus && m_posemps) {
m_posemps->add(pqe);
} else {
delete pqe;
}
} else if ( strcmp (record_type, "rppEmpDow") == 0) {
rppEmpDow *edow = new rppEmpDow;
if (!edow) { log("new edow failure"); return 0; }
istatus = edow->read_str(p);
if (istatus && m_empdows) {
m_empdows->add(edow);
} else {
delete edow;
}
} else if ( strcmp (record_type, "rppEmpOff") == 0) {
rppEmpOff *eoff = new rppEmpOff;
if (!eoff) { log("new eoff failure"); return 0; }
istatus = eoff->read_str(p);
if (istatus && m_empoffs) {
m_empoffs->add(eoff);
} else {
delete eoff;
}
} else if ( strcmp (record_type, "rppAssignment") == 0) {
rppAssignment *assg = new rppAssignment;
if (!assg) { log("new assg failure"); return 0; }
istatus = assg->read_str(p);
if (istatus && m_assignments) {
m_assignments->add(assg);
} else {
delete assg;
}
} else if ( strcmp (record_type, "rppEmpDayPos") == 0) {
rppEmpDayPos *edp = new rppEmpDayPos;
if (!edp) { log("new edp failure"); return 0; }
istatus = edp->read_str(p);
if (istatus && m_empdaypos) {
m_empdaypos->add(edp);
} else {
delete edp;
}
} else {
log("Read - bad record_type: ");
log(record_type);
return 0;
}
} // end of loop through records in input file
if (!istatus) {
log(" Error reading input: ");
log(buf);
}
fclose (ifp);
return istatus;
}
//----------------------------------------------------------------------
// Read data from string to setup this object
int rppProblem::read_str (const char *x) {
m_start_yyyymmdd = m_end_yyyymmdd = 19000101;
m_week_start_day = m_num_tries = 0;
char s_start_date[31], s_end_date[31];
if (x && *x) x = aip_get_str(x, 30, s_start_date, '|');
if (x && *x) x = aip_get_str(x, 30, s_end_date, '|');
if (x && *x) x = aip_get_val(x, 10, &m_week_start_day, '|');
if (x && *x) x = aip_get_val(x, 10, &m_num_tries, '|');
if (!x) return 0;
rppFileDate x_start_date(s_start_date);
if ( !x_start_date.is_valid() ) {
log("problem start-date must be set and valid");
return 0;
}
m_start_yyyymmdd = x_start_date.long_date();
if (m_start_yyyymmdd < 19000101 || m_start_yyyymmdd > 21000101) {
log("problem start-date must be between 1900 and 2100");
return 0;
}
rppFileDate x_end_date(s_end_date);
if ( !x_end_date.is_valid() ) {
log("problem end-date must be set and valid");
return 0;
}
m_end_yyyymmdd = x_end_date.long_date();
if (m_end_yyyymmdd < 19000101 || m_end_yyyymmdd > 21000101) {
log("problem end-date must be between 1900 and 2100");
return 0;
}
if (m_end_yyyymmdd < m_start_yyyymmdd) {
log("problem end-date must be after problem start-date");
return 0;
}
if (m_week_start_day < 1 || m_week_start_day > 7) {
log("week_start_day must be between 1 and 7");
return 0;
}
if (m_num_tries < 1 || m_num_tries > 100000) {
log("num_tries must be between 1 and 100000");
return 0;
}
return 1;
}
//----------------------------------------------------------------------
// Write the data in this object to the string; return 0 on failure
int rppProblem::write_str (char *x) const {
rppFileDate x_start_date(m_start_yyyymmdd);
if ( !x_start_date.is_valid() ) return 0;
rppFileDate x_end_date(m_end_yyyymmdd);
if ( !x_end_date.is_valid() ) return 0;
int n = sprintf (x, "rppProblem|%s|%s|%ld|%ld",
x_start_date.file_date(),
x_end_date.file_date(),
m_week_start_day,
m_num_tries);
return (n ? 1 : 0);
}
//----------------------------------------------------------------------
// Write the input data to a file; return 1 (true) on success
int rppProblem::write_input (const char *filename) {
FILE *ofp = fopen (filename, "w");
if (!ofp) {
log("Error opening export file");
return 0;
}
int n = 1;
if (n) n = fprintf (ofp, "# rrproj export file\n");
if (n) n = fprintf (ofp, "# \n");
char rec[1001];
if (n) n = write_str(rec);
if (n) n = fprintf (ofp, "%s\n", rec); // rppProblem record
rppPosDayItr pditr = posday_iterator();
rppPosDay *pd;
for (pd = pditr.first(); pd && n; pd = pditr.next()) {
if (n) n = pd->write_str(rec);
if (n) n = fprintf (ofp, "%s\n", rec);
}
rppPosEmpItr peitr = posemp_iterator();
rppPosEmp *pe;
for (pe = peitr.first(); pe && n; pe = peitr.next()) {
if (n) n = pe->write_str(rec);
if (n) n = fprintf (ofp, "%s\n", rec);
}
rppEmpDowItr edowitr = empdow_iterator();
rppEmpDow *edow;
for (edow = edowitr.first(); edow && n; edow = edowitr.next()) {
if (n) n = edow->write_str(rec);
if (n) n = fprintf (ofp, "%s\n", rec);
}
rppEmpOffItr eoffitr = empoff_iterator();
rppEmpOff *eoff;
for (eoff = eoffitr.first(); eoff && n; eoff = eoffitr.next()) {
if (n) n = eoff->write_str(rec);
if (n) n = fprintf (ofp, "%s\n", rec);
}
rppAssgnItr assgnitr = assgn_iterator();
rppAssignment *assgn;
for (assgn = assgnitr.first(); assgn && n; assgn = assgnitr.next()) {
if (n) n = assgn->write_str(rec);
if (n) n = fprintf (ofp, "%s\n", rec);
}
rppEmpDayPosItr edpitr = empdaypos_iterator();
rppEmpDayPos *edp;
for (edp = edpitr.first(); edp && n; edp = edpitr.next()) {
if (n) n = edp->write_str(rec);
if (n) n = fprintf (ofp, "%s\n", rec);
}
fclose(ofp);
if (!n) {
log("Error writing export file");
return 0;
}
return 1;
}
//----------------------------------------------------------------------
// Return a pointer to a description of the results of trying to
// to solve this problem.
const char * rppProblem::get_rslt_desc () const {
return m_logger->get();
}
//----------------------------------------------------------------------
// Add a Position-Day
void rppProblem::add_pos_day (long a_proj_id, long a_pos_id,
long a_yyyymmdd, long a_num_emps_req) {
rppPosDay *x = new rppPosDay (a_proj_id, a_pos_id,
a_yyyymmdd, a_num_emps_req);
if (x) m_posdays->add(x);
}
//----------------------------------------------------------------------
// Add an Employee-Day-of-week
void rppProblem::add_emp_dow (long a_emp_id, long a_dow,
long a_start_hhmm, long a_end_hhmm) {
rppEmpDow *x = new rppEmpDow (a_emp_id, a_dow,
a_start_hhmm, a_end_hhmm);
if (x) m_empdows->add(x);
}
//----------------------------------------------------------------------
// Add a Employee-Off
void rppProblem::add_emp_off (long a_emp_id,
long a_start_yyyymmdd,
long a_end_yyyymmdd) {
rppEmpOff *x = new rppEmpOff (a_emp_id,
a_start_yyyymmdd, a_end_yyyymmdd);
if (x) m_empoffs->add(x);
}
//----------------------------------------------------------------------
// Add a Position-Employee pair
void rppProblem::add_pos_emp (long a_pos_id, long a_emp_id) {
rppPosEmp *x = new rppPosEmp (a_pos_id, a_emp_id);
if (x) m_posemps->add(x);
}
//----------------------------------------------------------------------
// Add an Assignment
void rppProblem::add_assignment (long a_proj_id, long a_pos_id,
long a_emp_id,
long a_start_yyyymmdd,
long a_end_yyyymmdd) {
rppAssignment *x = new rppAssignment (a_proj_id, a_pos_id, a_emp_id,
a_start_yyyymmdd, a_end_yyyymmdd);
if (x) m_assignments->add(x);
}
//----------------------------------------------------------------------
// Add an historic Emp-Day-Pos
void rppProblem::add_empdaypos (long a_emp_id, long a_yyyymmdd,
long a_proj_id, long a_pos_id) {
rppEmpDayPos *x = new rppEmpDayPos (a_emp_id, a_yyyymmdd,
a_proj_id, a_pos_id);
if (x) m_empdaypos->add(x);
}
//----------------------------------------------------------------------
// Add a Position-Day-Employee
void rppProblem::add_posdayemp (long a_proj_id, long a_pos_id,
long a_yyyymmdd, long a_emp_id) {
rppPosDayEmp *x = new rppPosDayEmp (a_proj_id, a_pos_id,
a_yyyymmdd, a_emp_id);
if (x) m_posdayemps->add(x);
}
//----------------------------------------------------------------------
// Attempt to solve the rrproj problem
//
// A description of the result of calling this function is logged.
//
// Return 1 (true) if a solution is found, 0 otherwise.
int rppProblem::solve () {
rpfFactory *factory = new rpfFactory(this);
if (!factory) {
log("ABORT - could not make factory");
return 0;
}
rpsProblem * rps_problem = factory->make_rps_problem();
if (!rps_problem) {
log("ABORT - error creating rps_problem");
return 0;
}
delete factory;
// rps_problem->enable_log_tries();
rps_problem->disable_log_tries();
// rps_problem->enable_log_options();
rps_problem->disable_log_options();
int status = rps_problem->solve_rr_problem();
if (status) {
log("Solution found.");
save_solution(this, rps_problem);
} else {
log("Solution was not found.");
}
delete rps_problem;
return status;
}
//----------------------------------------------------------------------
// get_pos_day_emp - get a solution datum, or zero after last
int rppProblem::get_pos_day_emp (long *a_proj_id, long *a_pos_id,
long *a_yyyymmdd, long *a_emp_id) {
rppPosDayEmp *pde;
if (m_posdayemp_itr) {
pde = m_posdayemp_itr->next();
} else {
m_posdayemp_itr = new rppPosDayEmpItr(m_posdayemps);
pde = m_posdayemp_itr->first();
}
if (!pde) return 0;
*a_proj_id = pde->proj_id();
*a_pos_id = pde->pos_id();
*a_yyyymmdd = pde->yyyymmdd();
*a_emp_id = pde->emp_id();
return 1;
}
//----------------------------------------------------------------------
// Get an iterator for Position-Days in a problem
rppPosDayItr rppProblem::posday_iterator () const {
rppPosDayItr i(m_posdays);
return i;
}
//----------------------------------------------------------------------
// Get an iterator for Employee-Days-of-week in a problem
rppEmpDowItr rppProblem::empdow_iterator () const {
rppEmpDowItr i(m_empdows);
return i;
}
//----------------------------------------------------------------------
// Get an iterator for Employee-days-Off in a problem
rppEmpOffItr rppProblem::empoff_iterator () const {
rppEmpOffItr i(m_empoffs);
return i;
}
//----------------------------------------------------------------------
// Get an iterator for Position-Employee pairs in a problem
rppPosEmpItr rppProblem::posemp_iterator () const {
rppPosEmpItr i(m_posemps);
return i;
}
//----------------------------------------------------------------------
// Get an iterator for Assignments in a problem
rppAssgnItr rppProblem::assgn_iterator () const {
rppAssgnItr i(m_assignments);
return i;
}
//----------------------------------------------------------------------
// Get an iterator for historic Emp-Day-Pos in a problem
rppEmpDayPosItr rppProblem::empdaypos_iterator () const {
rppEmpDayPosItr i(m_empdaypos);
return i;
}
//----------------------------------------------------------------------
// Get an iterator for Position-Day-Employees in a problem
rppPosDayEmpItr rppProblem::posdayemp_iterator () const {
rppPosDayEmpItr i(m_posdayemps);
return i;
}
//======================================================================
// rppPosDay
//
//----------------------------------------------------------------------
// Constructor
rppPosDay::rppPosDay (long a_proj_id, long a_pos_id,
long a_yyyymmdd, long a_num_emps_req,
long a_start_hhmm, long a_end_hhmm) {
m_proj_id = a_proj_id;
m_pos_id = a_pos_id;
m_yyyymmdd = a_yyyymmdd;
m_num_emps_req = a_num_emps_req;
m_start_hhmm = a_start_hhmm;
m_end_hhmm = a_end_hhmm;
}
//----------------------------------------------------------------------
// Destructor
rppPosDay::~rppPosDay () {}
//----------------------------------------------------------------------
// Read data from string to setup this object
int rppPosDay::read_str (const char *x) {
m_proj_id = m_pos_id = m_yyyymmdd = 0;
m_num_emps_req = m_start_hhmm = m_end_hhmm = 0;
char s_date[31], s_start_time[31], s_end_time[31];
if (x && *x) x = aip_get_val(x, 10, &m_proj_id, '|');
if (x && *x) x = aip_get_val(x, 10, &m_pos_id, '|');
if (x && *x) x = aip_get_str(x, 30, s_date, '|');
if (x && *x) x = aip_get_val(x, 10, &m_num_emps_req, '|');
if (x && *x) x = aip_get_str(x, 30, s_start_time, '|');
if (x && *x) x = aip_get_str(x, 30, s_end_time, '|');
if (!x) return 0;
rppFileDate x_date(s_date);
if ( !x_date.is_valid() ) return 0;
m_yyyymmdd = x_date.long_date();
rppFileTime x_start_time(s_start_time);
if ( !x_start_time.is_valid() ) return 0;
m_start_hhmm = x_start_time.long_time();
rppFileTime x_end_time(s_end_time);
if ( !x_end_time.is_valid() ) return 0;
m_end_hhmm = x_end_time.long_time();
return 1;
}
//----------------------------------------------------------------------
// Write the data in this object to the string; return 0 on failure
int rppPosDay::write_str (char *x) const {
rppFileDate x_date(m_yyyymmdd);
if ( !x_date.is_valid() ) return 0;
rppFileTime x_start_time(m_start_hhmm);
if ( !x_start_time.is_valid() ) return 0;
rppFileTime x_end_time(m_end_hhmm);
if ( !x_end_time.is_valid() ) return 0;
int n = sprintf (x, "rppPosDay|%ld|%ld|%s|%ld|%s|%s",
m_proj_id, m_pos_id,
x_date.file_date(),
m_num_emps_req,
x_start_time.file_time(),
x_end_time.file_time());
return (n ? 1 : 0);
}
//======================================================================
// rppEmpDow
//
//----------------------------------------------------------------------
// Constructor
rppEmpDow::rppEmpDow (long a_emp_id, long a_dow,
long a_start_hhmm, long a_end_hhmm) {
m_emp_id = a_emp_id;
m_dow = a_dow;
m_start_hhmm = a_start_hhmm;
m_end_hhmm = a_end_hhmm;
}
//----------------------------------------------------------------------
// Destructor
rppEmpDow::~rppEmpDow () {}
//----------------------------------------------------------------------
// Read data from string to setup this object
int rppEmpDow::read_str (const char *x) {
char s_start_time[31], s_end_time[31];
if (x && *x) x = aip_get_val(x, 10, &m_emp_id, '|');
if (x && *x) x = aip_get_val(x, 10, &m_dow, '|');
if (x && *x) x = aip_get_str(x, 30, s_start_time, '|');
if (x && *x) x = aip_get_str(x, 30, s_end_time, '|');
if (!x) return 0;
rppFileTime x_start_time(s_start_time);
if ( !x_start_time.is_valid() ) return 0;
m_start_hhmm = x_start_time.long_time();
rppFileTime x_end_time(s_end_time);
if ( !x_end_time.is_valid() ) return 0;
m_end_hhmm = x_end_time.long_time();
return 1;
}
//----------------------------------------------------------------------
// Write the data in this object to the string; return 0 on failure
int rppEmpDow::write_str (char *x) const {
rppFileTime x_start_time(m_start_hhmm);
if ( !x_start_time.is_valid() ) return 0;
rppFileTime x_end_time(m_end_hhmm);
if ( !x_end_time.is_valid() ) return 0;
int n = sprintf (x, "rppEmpDow|%ld|%ld|%s|%s",
m_emp_id, m_dow,
x_start_time.file_time(),
x_end_time.file_time());
return (n ? 1 : 0);
}
//======================================================================
// rppEmpOff
//
//----------------------------------------------------------------------
// Constructor
rppEmpOff::rppEmpOff (long a_emp_id,
long a_start_yyyymmdd, long a_end_yyyymmdd) {
m_emp_id = a_emp_id;
m_start_yyyymmdd = a_start_yyyymmdd;
m_end_yyyymmdd = a_end_yyyymmdd;
derive_data();
}
//----------------------------------------------------------------------
// Destructor
rppEmpOff::~rppEmpOff () {}
//----------------------------------------------------------------------
// Derive data
void rppEmpOff::derive_data() {
m_start_day = aipTime(m_start_yyyymmdd);
m_end_day = aipTime(m_end_yyyymmdd);
}
//----------------------------------------------------------------------
// Read data from string to setup this object
int rppEmpOff::read_str (const char *x) {
char s_start_date[31], s_end_date[31];
if (x && *x) x = aip_get_val(x, 10, &m_emp_id, '|');
if (x && *x) x = aip_get_str(x, 30, s_start_date, '|');
if (x && *x) x = aip_get_str(x, 30, s_end_date, '|');
if (!x) return 0;
rppFileDate x_start_date(s_start_date);
if ( !x_start_date.is_valid() ) return 0;
m_start_yyyymmdd = x_start_date.long_date();
rppFileDate x_end_date(s_end_date);
if ( !x_end_date.is_valid() ) return 0;
m_end_yyyymmdd = x_end_date.long_date();
if (x) derive_data(); // must get called
return 1;
}
//----------------------------------------------------------------------
// Write the data in this object to the string; return 0 on failure
int rppEmpOff::write_str (char *x) const {
rppFileDate x_start_date(m_start_yyyymmdd);
if ( !x_start_date.is_valid() ) return 0;
rppFileDate x_end_date(m_end_yyyymmdd);
if ( !x_end_date.is_valid() ) return 0;
int n = sprintf (x, "rppEmpOff|%ld|%s|%s",
m_emp_id,
x_start_date.file_date(),
x_end_date.file_date());
return (n ? 1 : 0);
}
//======================================================================
// rppPosEmp
//
//----------------------------------------------------------------------
// Constructor
rppPosEmp::rppPosEmp (long a_pos_id, long a_emp_id) {
m_pos_id = a_pos_id;
m_emp_id = a_emp_id;
}
//----------------------------------------------------------------------
// Destructor
rppPosEmp::~rppPosEmp () {}
//----------------------------------------------------------------------
// Read data from string to setup this object
int rppPosEmp::read_str (const char *x) {
if (x && *x) x = aip_get_val(x, 10, &m_pos_id, '|');
if (x && *x) x = aip_get_val(x, 10, &m_emp_id, '|');
return (x ? 1 : 0);
}
//----------------------------------------------------------------------
// Write the data in this object to the string; return 0 on failure
int rppPosEmp::write_str (char *x) const {
int n = sprintf (x, "rppPosEmp|%ld|%ld",
m_pos_id, m_emp_id);
return (n ? 1 : 0);
}
//======================================================================
// rppAssignment
//
//----------------------------------------------------------------------
// Constructor
rppAssignment::rppAssignment (long a_proj_id, long a_pos_id,
long a_emp_id,
long a_start_yyyymmdd,
long a_end_yyyymmdd) {
m_proj_id = a_proj_id;
m_pos_id = a_pos_id;
m_emp_id = a_emp_id;
m_start_yyyymmdd = a_start_yyyymmdd;
m_end_yyyymmdd = a_end_yyyymmdd;
}
//----------------------------------------------------------------------
// Destructor
rppAssignment::~rppAssignment () {}
//----------------------------------------------------------------------
// Read data from string to setup this object
int rppAssignment::read_str (const char *x) {
char s_start_date[31], s_end_date[31];
if (x && *x) x = aip_get_val(x, 10, &m_proj_id, '|');
if (x && *x) x = aip_get_val(x, 10, &m_pos_id, '|');
if (x && *x) x = aip_get_val(x, 10, &m_emp_id, '|');
if (x && *x) x = aip_get_str(x, 10, s_start_date, '|');
if (x && *x) x = aip_get_str(x, 10, s_end_date, '|');
if (!x) return 0;
rppFileDate x_start_date(s_start_date);
if ( !x_start_date.is_valid() ) return 0;
m_start_yyyymmdd = x_start_date.long_date();
rppFileDate x_end_date(s_end_date);
if ( !x_end_date.is_valid() ) return 0;
m_end_yyyymmdd = x_end_date.long_date();
return 1;
}
//----------------------------------------------------------------------
// Write the data in this object to the string; return 0 on failure
int rppAssignment::write_str (char *x) const {
rppFileDate x_start_date(m_start_yyyymmdd);
if ( !x_start_date.is_valid() ) return 0;
rppFileDate x_end_date(m_end_yyyymmdd);
if ( !x_end_date.is_valid() ) return 0;
int n = sprintf (x, "rppAssignment|%ld|%ld|%ld|%s|%s",
m_proj_id, m_pos_id, m_emp_id,
x_start_date.file_date(),
x_end_date.file_date());
return (n ? 1 : 0);
}
//======================================================================
// rppEmpDayPos
//
//----------------------------------------------------------------------
// Constructor
rppEmpDayPos::rppEmpDayPos (long a_emp_id, long a_yyyymmdd,
long a_proj_id, long a_pos_id) {
m_emp_id = a_emp_id;
m_yyyymmdd = a_yyyymmdd;
m_proj_id = a_proj_id;
m_pos_id = a_pos_id;
}
//----------------------------------------------------------------------
// Destructor
rppEmpDayPos::~rppEmpDayPos () {}
//----------------------------------------------------------------------
// Read data from string to setup this object
int rppEmpDayPos::read_str (const char *x) {
char s_date[31];
if (x && *x) x = aip_get_val(x, 10, &m_emp_id, '|');
if (x && *x) x = aip_get_str(x, 30, s_date, '|');
if (x && *x) x = aip_get_val(x, 10, &m_proj_id, '|');
if (x && *x) x = aip_get_val(x, 10, &m_pos_id, '|');
if (!x) return 0;
rppFileDate x_date(s_date);
if ( !x_date.is_valid() ) return 0;
m_yyyymmdd = x_date.long_date();
return 1;
}
//----------------------------------------------------------------------
// Write the data in this object to the string; return 0 on failure
int rppEmpDayPos::write_str (char *x) const {
rppFileDate x_date(m_yyyymmdd);
if ( !x_date.is_valid() ) return 0;
int n = sprintf (x, "rppEmpDayPos|%ld|%s|%ld|%ld",
m_emp_id, x_date.file_date(),
m_proj_id, m_pos_id);
return (n ? 1 : 0);
}
//======================================================================
// rppProjWeekEmpDay
//
//----------------------------------------------------------------------
// Constructor
rppProjWeekEmpDay::rppProjWeekEmpDay () {
m_proj_id = m_week_num = m_emp_id = 0;
m_week_pos = m_yyyymmdd = m_pos_id = 0;
}
//----------------------------------------------------------------------
// Destructor
rppProjWeekEmpDay::~rppProjWeekEmpDay () {}
//----------------------------------------------------------------------
// Set the data members
void rppProjWeekEmpDay::set (long a_proj_id, long a_week_num,
long a_emp_id, long a_week_pos,
long a_yyyymmdd, long a_pos_id) {
m_proj_id = a_proj_id;
m_week_num = a_week_num;
m_emp_id = a_emp_id;
m_week_pos = a_week_pos;
m_yyyymmdd = a_yyyymmdd;
m_pos_id = a_pos_id;
}
//======================================================================
// rppPosDayEmp
//
//----------------------------------------------------------------------
// Constructor
rppPosDayEmp::rppPosDayEmp (long a_proj_id, long a_pos_id,
long a_yyyymmdd, long a_emp_id) {
m_proj_id = a_proj_id;
m_pos_id = a_pos_id;
m_yyyymmdd = a_yyyymmdd;
m_emp_id = a_emp_id;
}
//----------------------------------------------------------------------
// Destructor
rppPosDayEmp::~rppPosDayEmp () {}
//----------------------------------------------------------------------
// Write the header for the data in this object
int rppPosDayEmp::write_hdr (char *x) const {
int n = sprintf (x, "\n#rppPosDayEmp|proj_id|pos_id|date|emp_id");
return (n ? 1 : 0);
}
//----------------------------------------------------------------------
// Write the data in this object to the string; return 0 on failure
int rppPosDayEmp::write_str (char *x) const {
rppFileDate x_date(m_yyyymmdd);
if ( !x_date.is_valid() ) return 0;
int n = sprintf (x, "rppPosDayEmp|%ld|%ld|%s|%ld",
m_proj_id, m_pos_id,
x_date.file_date(), m_emp_id);
return (n ? 1 : 0);
}
//======================================================================
// rppProbWrite
//
//----------------------------------------------------------------------
// Constructor
rppProbWrite::rppProbWrite (const rppProblem *x,
const char * out_file_name)
: m_prob(x) {
if (out_file_name) {
aip_strncpy (m_out_file_name, out_file_name, Max_File_Name);
}
m_any_pos_day_emp_written = 0;
}
//----------------------------------------------------------------------
// Destructor
rppProbWrite::~rppProbWrite () {}
//----------------------------------------------------------------------
// Write the solution data - return zero on error
int rppProbWrite::write () {
FILE *ofp = fopen (m_out_file_name, "w");
if (!ofp) {
log("Error opening output file: ");
log(m_out_file_name);
return 0;
}
if ( !pre_proc(ofp) ) return 0;
rppPosDayEmpItr pdeitr = m_prob->posdayemp_iterator();
rppPosDayEmp *pde;
for (pde = pdeitr.first(); pde; pde = pdeitr.next()) {
if ( !handle_pos_day_emp(ofp, pde) ) return 0;
} // end of loop through pos-day-emp data
if ( !post_proc(ofp) ) return 0;
fclose(ofp);
return 1;
}
//----------------------------------------------------------------------
// pre_proc - called before solution-detail data is handled
int rppProbWrite::pre_proc (FILE *ofp) {
if (!ofp) return 0;
int n = 1;
if (n) n = fprintf (ofp, "# rrproj output file\n\n");
if (n) n = fprintf (ofp, "rppRsltDscr|%s\n",
m_prob->get_rslt_desc());
if (!n) {
log("Error writing beginning of output file");
return 0;
}
return 1;
}
//----------------------------------------------------------------------
// handle a normalized solution detail
int rppProbWrite::handle_pos_day_emp (FILE *ofp,
const rppPosDayEmp *pde) {
if (!ofp || !pde) return 0;
char rec[201];
if (!m_any_pos_day_emp_written) {
if ( !pde->write_hdr(rec) ) {
log("Error writing pos-emp-day header to the output string");
return 0;
}
if ( !fprintf (ofp, "%s\n", rec) ) {
log("Error writing pos-emp-day header to the output file");
return 0;
}
m_any_pos_day_emp_written = 1;
}
if ( !pde->write_str(rec) ) {
log("Error writing pos-emp-day data to the output string");
return 0;
}
if ( !fprintf (ofp, "%s\n", rec) ) {
log("Error writing pos-emp-day data to the output file");
return 0;
}
return 1;
}
//----------------------------------------------------------------------
// post_proc - called after solution-detail data is handled
int rppProbWrite::post_proc (FILE *ofp) {
if (!ofp) return 0;
return 1;
}
//----------------------------------------------------------------------
// write a blank line to the output file
int rppProbWrite::write_blank_line (FILE *ofp) {
if (!ofp) return 0;
if ( !fprintf (ofp, "\n") ) {
log("Error writing blank line to the output file");
return 0;
}
return 1;
}
//======================================================================
// rppProbWriteWeek1
//
//----------------------------------------------------------------------
// Constructor
rppProbWriteWeek1::rppProbWriteWeek1 (const rppProblem *x,
const char *out_file_name)
: rppProbWrite(x,out_file_name) {
set_week1_start_dt();
m_proj_week_emp_days = new aipPandemonium;
if (!m_proj_week_emp_days) { log("new m_proj_week_emp_days error"); }
m_proj_week = new rppProjWeek;
if (!m_proj_week) { log("new m_proj_week error"); }
m_proj_week_emp = new rppProjWeekEmp;
if (!m_proj_week_emp) { log("new m_proj_week_emp error"); }
reset();
}
//----------------------------------------------------------------------
// Destructor
rppProbWriteWeek1::~rppProbWriteWeek1 () {
if (m_proj_week_emp_days) delete m_proj_week_emp_days;
if (m_proj_week) delete m_proj_week;
if (m_proj_week_emp) delete m_proj_week_emp;
}
//----------------------------------------------------------------------
// Return zero if this object is not valid
int rppProbWriteWeek1::is_valid () const {
if (!m_proj_week_emp_days ||
!m_proj_week || !m_proj_week_emp) return 0;
return 1;
}
//----------------------------------------------------------------------
// Reset current data - ie. everything except m_week1_start_dt
void rppProbWriteWeek1::reset () {
if (!is_valid()) return;
m_proj_week->reset();
m_proj_week_emp->reset();
m_any_week_data = m_any_emp_data = 0;
}
//----------------------------------------------------------------------
// Set the date of the first day of week 1
void rppProbWriteWeek1::set_week1_start_dt () {
aipTime prob_start_dt(prob()->start_yyyymmdd());
aipTime prob_end_dt(prob()->end_yyyymmdd());
m_week1_start_dt = prob_start_dt;
long prob_start_day = prob_start_dt.days_since_sunday();
long wk_offset = (prob_start_day + 7 - prob()->week_start_day()) % 7;
if (wk_offset) {
wk_offset = 0 - wk_offset; // now zero or negative
m_week1_start_dt.add_days(wk_offset);
}
// if the problem will fit into a week, force it if necessary
long prob_num_days = prob_end_dt.days_since(prob_start_dt) + 1;
if (prob_num_days <= 7) {
long wnum1, wpos1, wnum2, wpos2;
if( !week_dt(prob_start_dt, &wnum1, &wpos1) ) return;
if( !week_dt(prob_end_dt, &wnum2, &wpos2) ) return;
if (wnum1 != wnum2) {
m_week1_start_dt = prob_start_dt;
}
}
}
//----------------------------------------------------------------------
// Determine the week-number and week_position (1 to 7) of a date.
// Return zero on failure.
int rppProbWriteWeek1::week_dt (aipTime x,
long *week_num, long *week_pos) const {
if ( !week_num || !week_pos ) return 0;
long a, b;
long ddif = x.days_after(m_week1_start_dt);
if (ddif < -50000 || ddif > 50000) return 0;
if (ddif >= 0) {
a = 0; b = 1;
} else {
a = 1; b = 0;
}
*week_num = (ddif + a) / 7 + b;
*week_pos = ((ddif + 70000) % 7) + 1;
return 1;
}
//----------------------------------------------------------------------
// handle a normalized solution detail
//
// add the data to m_proj_week_emp_days to reorder it
int rppProbWriteWeek1::handle_pos_day_emp (FILE *ofp,
const rppPosDayEmp *pde) {
if (!ofp || !pde || !is_valid()) return 0;
rppProjWeekEmpDay *pwed = new rppProjWeekEmpDay;
if (!pwed) { log("new rppProjWeekEmpDay error"); return 0; }
long wnum, wpos;
week_dt (pde->yyyymmdd(), &wnum, &wpos);
pwed->set ( pde->proj_id(), wnum, pde->emp_id(),
wpos, pde->yyyymmdd(), pde->pos_id() );
if (m_proj_week_emp_days) m_proj_week_emp_days->add(pwed);
return 1;
}
//----------------------------------------------------------------------
// post_proc - called after solution-detail data is handled
int rppProbWriteWeek1::post_proc (FILE *ofp) {
if (!ofp || !is_valid()) return 0;
int have_written_week_hdr = 0;
int have_written_emp_hdr = 0;
if ( !write_blank_line(ofp) ) return 0;
rppProjWeekEmpDayItr pwed_itr = projweekempday_iterator();
rppProjWeekEmpDay *pwed;
for (pwed=pwed_itr.first(); pwed; pwed=pwed_itr.next()) {
if (m_any_week_data) {
if (pwed->proj_id() != m_proj_week->proj_id() ||
pwed->week_num() != m_proj_week->week_num()) {
m_proj_week->reset();
m_any_week_data = 0;
}
}
if (m_any_emp_data) {
if (pwed->proj_id() != m_proj_week_emp->proj_id() ||
pwed->week_num() != m_proj_week_emp->week_num() ||
pwed->emp_id() != m_proj_week_emp->emp_id()) {
if (!have_written_emp_hdr) {
if ( !m_proj_week_emp->write_hdr(ofp) ) return 0;
have_written_emp_hdr = 1;
}
if ( !m_proj_week_emp->write(ofp) ) return 0;
m_proj_week_emp->reset();
m_any_emp_data = 0;
}
}
if (!m_any_week_data) {
if (!have_written_week_hdr) {
if ( !m_proj_week->write_hdr(ofp) ) return 0;
have_written_week_hdr = 1;
}
if ( !set_proj_week(pwed) ) return 0; // set whole week
if ( !m_proj_week->write(ofp) ) return 0;
if ( !m_any_week_data ) m_any_week_data = 1;
}
if ( !add_to_proj_week_emp(pwed) ) return 0; // set one day
if (!m_any_emp_data) m_any_emp_data = 1;
} // end of loop through proj-week-emp-days
if (m_any_emp_data) {
if (!have_written_emp_hdr) {
if ( !m_proj_week_emp->write_hdr(ofp) ) return 0;
// have_written_emp_hdr = 1; not used
}
if ( !m_proj_week_emp->write(ofp) ) return 0;
m_proj_week->reset();
m_proj_week_emp->reset();
m_any_emp_data = 0;
}
return 1;
}
//----------------------------------------------------------------------
// set m_proj_week for the week containing pwed
int rppProbWriteWeek1::set_proj_week (rppProjWeekEmpDay *pwed) {
m_proj_week->set_pw (pwed->proj_id(), pwed->week_num());
aipTime x_dt(pwed->yyyymmdd());
long diff = 1 - pwed->week_pos(); // zero or negative
if (diff) x_dt.add_days(diff);
long x_yyyymmdd;
for (int iday=1; iday<=7; iday++) {
x_yyyymmdd = x_dt.yyyymmdd();
m_proj_week->set_day (iday, x_yyyymmdd);
x_dt.add_days(1);
}
return 1;
}
//----------------------------------------------------------------------
// set m_proj_week_emp for the day of pwed
// set key data members if required
int rppProbWriteWeek1::add_to_proj_week_emp (rppProjWeekEmpDay *pwed) {
if (!m_any_emp_data) {
m_proj_week_emp->set_pwe (pwed->proj_id(),
pwed->week_num(), pwed->emp_id());
}
m_proj_week_emp->set_day(pwed->week_pos(), pwed->pos_id());
return 1;
}
//----------------------------------------------------------------------
// Get an iterator for Proj-Week-Emp-Day in a Prob-Write-Week1
rppProjWeekEmpDayItr
rppProbWriteWeek1::projweekempday_iterator () const {
rppProjWeekEmpDayItr i(m_proj_week_emp_days);
return i;
}
//======================================================================
// rppProjWeek
//
//----------------------------------------------------------------------
// reset this master-data
void rppProjWeek::reset () {
m_proj_id = m_week_num = -1;
for (int i=0; i<7; i++) m_yyyymmdd[i] = -1;
}
//----------------------------------------------------------------------
// Write the header for the data in this object to the string;
// return 0 on failure
int rppProjWeek::write_hdr (char *x) const {
int n = sprintf (x, "#rppProjWeek|proj|week|...");
return (n ? 1 : 0);
}
//----------------------------------------------------------------------
// Write the header for the data in this object to a file;
// return 0 on failure
int rppProjWeek::write_hdr (FILE *ofp) const {
char rec[201];
if ( !write_hdr(rec) ) {
log("Error writing proj_week to header string");
return 0;
}
if ( !fprintf (ofp, "%s\n", rec) ) {
log("Error writing proj_week to header file");
return 0;
}
return 1;
}
//----------------------------------------------------------------------
// Write the data in this object to the string; return 0 on failure
int rppProjWeek::write_str (char *x) const {
long l_dom; // dom = day-of-month
char s_mon[4], s_dow[4]; // dow = day-of-week
int nn = sprintf (x, "rppProjWeek|%ld|%ld", m_proj_id, m_week_num);
if (!nn) return 0;
int n = nn; // total chars written = chars just written
for (int i=0; i<7; i++) {
if (m_yyyymmdd[i] <= 0) return 0;
aipTime dt(m_yyyymmdd[i]);
if (!dt.is_valid()) return 0;
dt.get (0, 0, &l_dom, 0, 0, 0, s_mon, s_dow);
if (i != 0 && l_dom != 1) strcpy (s_mon, " ");
nn = sprintf (x+n, "|%s|%ld|%s", s_mon, l_dom, s_dow);
if (!nn) return 0;
n += nn;
} // end of loop through day in week
return 1;
}
//----------------------------------------------------------------------
// Write the data in this object to a file; return 0 on failure
int rppProjWeek::write (FILE *ofp) const {
char rec[201];
if ( !write_str(rec) ) {
log("Error writing proj_week to output string");
return 0;
}
if ( !fprintf (ofp, "%s\n", rec) ) {
log("Error writing proj_week to output file");
return 0;
}
return 1;
}
//======================================================================
// rppProjWeekEmp
//
//----------------------------------------------------------------------
// Reset this set of detail data
void rppProjWeekEmp::reset () {
m_proj_id = m_week_num = m_emp_id = -1;
for (int i=0; i<7; i++) m_pos_id[i] = -1;
}
//----------------------------------------------------------------------
// Write the header for the data in this object to the string;
// return 0 on failure
int rppProjWeekEmp::write_hdr (char *x) const {
char fmt[201];
strcpy (fmt, "#rppProjWeekEmp|proj|week|emp");
strcat (fmt, "|day1pos_id|day2pos_id|...");
int n = sprintf (x, fmt);
return (n ? 1 : 0);
}
//----------------------------------------------------------------------
// Write the header for the data in this object to a file;
// return 0 on failure
int rppProjWeekEmp::write_hdr (FILE *ofp) const {
char rec[201];
if ( !write_hdr(rec) ) {
log("Error writing proj_week_emp to header string");
return 0;
}
if ( !fprintf (ofp, "%s\n", rec) ) {
log("Error writing proj_week_emp to header file");
return 0;
}
return 1;
}
//----------------------------------------------------------------------
// Write the data in this object to the string; return 0 on failure
int rppProjWeekEmp::write_str (char *x) const {
int nn = sprintf (x, "rppProjWeekEmp|%ld|%ld|%ld",
m_proj_id, m_week_num, m_emp_id);
if (!nn) return 0;
int n = nn; // total chars written = chars just written
for (int i=0; i<7; i++) {
if (m_pos_id[i] >= 0) {
nn = sprintf (x+n, "|%ld", m_pos_id[i]);
} else {
nn = sprintf (x+n, "| ");
}
if (!nn) return 0;
n += nn;
} // end of loop through day in week
return 1;
}
//----------------------------------------------------------------------
// Write the data in this object to a file; return 0 on failure
int rppProjWeekEmp::write (FILE *ofp) const {
char rec[201];
if ( !write_str(rec) ) {
log("Error writing proj_week_emp to output string");
return 0;
}
if ( !fprintf (ofp, "%s\n", rec) ) {
log("Error writing proj_week_emp to output file");
return 0;
}
return 1;
}
//======================================================================
// Iterators
//
// All function bodies are in the header file
//
//======================================================================
// rppFileDate
//
//----------------------------------------------------------------------
// Constructor - from a string "yyyy-mm-dd"
rppFileDate::rppFileDate (const char *a_yyyy_mm_dd) {
char *p = m_yyyy_mm_dd;
aip_strncpy (p, a_yyyy_mm_dd, File_Date_Len);
if ( strlen(p) != File_Date_Len) { reset(); return; }
p[4] = p[7] = '\0';
long yr = atol(p);
long mo = atol(p+5);
long dy = atol(p+8);
if ( yr < 1800 || yr > 2300 ||
mo < 1 || mo > 12 ||
dy < 1 || dy > aip_days_in_month(yr,mo) ) { reset(); return; }
m_yyyymmdd = yr*10000 + mo*100 + dy;
}
//----------------------------------------------------------------------
// Constructor - from a long yyyymmdd
rppFileDate::rppFileDate (long a_yyyymmdd) {
long yr = a_yyyymmdd / 10000;
a_yyyymmdd -= (yr * 10000);
long mo = a_yyyymmdd / 100;
a_yyyymmdd -= (mo * 100);
long dy = a_yyyymmdd;
if ( yr < 1800 || yr > 2300 ||
mo < 1 || mo > 12 ||
dy < 1 || dy > aip_days_in_month(yr,mo) ) { reset(); return; }
sprintf (m_yyyy_mm_dd, "%ld-%02ld-%02ld", yr, mo, dy);
}
//----------------------------------------------------------------------
// Destructor
rppFileDate::~rppFileDate () {}
//----------------------------------------------------------------------
// Return true if the date is valid
int rppFileDate::is_valid () {
return ( m_yyyymmdd ? 1 : 0 );
}
//======================================================================
// rppFileTime
//
//----------------------------------------------------------------------
// Constructor - from a string "hh:mm"
rppFileTime::rppFileTime (const char *a_hh_mm) {
char *p = m_hh_mm;
aip_strncpy (p, a_hh_mm, File_Time_Len);
if ( strlen(p) != File_Time_Len) { reset(); return; }
if (p[1] == ':') {
p[1] = '\0';
} else {
p[2] = '\0';
}
long hr = atol(p);
long mn = atol(p+3);
if ( hr < 0 || hr > 23 ||
mn < 0 || mn > 59 ) { reset(); return; }
m_hhmm = hr*100 + mn;
}
//----------------------------------------------------------------------
// Constructor - from a long hhmm
rppFileTime::rppFileTime (long a_hhmm) {
long hr = a_hhmm / 100;
a_hhmm -= (hr * 100);
long mn = a_hhmm;
if ( hr < 0 || hr > 23 ||
mn < 0 || mn > 59 ) { reset(); return; }
sprintf (m_hh_mm, "%02ld:%02ld", hr, mn);
}
//----------------------------------------------------------------------
// Destructor
rppFileTime::~rppFileTime () {}
//----------------------------------------------------------------------
// Return true if the time is valid
int rppFileTime::is_valid () {
return ( m_hhmm<2400 ? 1 : 0 );
}
//======================================================================
// License
//
// Permission is hereby granted, free of charge, to any
// person obtaining a copy of this software and associated
// documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to
// whom the Software is furnished to do so, subject to the
// following conditions:
//
// The copyright notice and this license shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
//
//======================================================================
|