// Topup management toosl
#include "clog.h"
#include "cgi.h"
#include "input.h"
#include "mermsemr_api.h"
#include "safestring.h"
#include <string>
#include "pgsql.h"
#include "pgsql_wrapper.h"
#include <curl/curl.h>
#include "medTEmails.h"

#include <algorithm> 
#include <cctype>
#include <locale>



/*
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
 */

/* -- */
#include "function_members.h"
#include "common_tool.h"

long MemberLogin(CVars in, CVars &out) {
    long ret = PHP_API_BAD_PARAM;

    try {
        REQ_STRING(in, "username", 2, 49, "(.*)");
        REQ_STRING(in, "password", 2, 49, "(.*)");
        const char * loc = getenv("REMOTE_ADDR");
        ret = load_db_record(out, "SELECT UPPER( md5( now()::text) ) AS sessionid,m.*,mp.*,m.id AS member_id,mp.id AS member_profile_id FROM members m \
			            LEFT JOIN members_profile mp ON mp.member_id = m.id \
			            WHERE m.status=1 AND LOWER(m.username)=LOWER('%s') AND m.password= md5('%s')", in["username"].c_str(), in["password"].c_str());
        if (ret && out["member_id"].Long() > 0) {
            // remove all existing session
            pgsql_exec("DELETE FROM members_session WHERE member_id=%ld ", out["member_id"].Long());
            // Create New Session Now
            if (MemberSessionCheck(out["member_id"].Long(), out["sessionid"].c_str(), 1) > 0) {

                out["acc_link"] = "ME345FT6789";
                GetMemberAccountLink(out["member_id"].Long(),out);
                // out["acc_link"] = acc_link;

                out["stauts"] = "OK";
                /*LOAD THE SESSION INTO OUT now */
                load_db_record(out, "SELECT session FROM members_session WHERE member_id=%lu ORDER BY id DESC LIMIT 1", out["member_id"].Long());
                member_email_calls(in["action"].Long(), out, out);
                //===============================================================================================================================
                pgsql_query("UPDATE members SET last_login = now() WHERE id  = %lu", out["member_id"].Long());
                // account_email(ACCOUNT_LOGIN_ALERT,out,out); // ALERT CUSTOMER OF LOGIN
                ret = PHP_LOGIN_OK;
            } else {
                out["status"] = "Session check failed";
            }


        } else {
            out["status_message"] = "Invalid Username/Password";
        }


    } catch (bad_parameter) {
        logfmt(logINFO, "ERROR CALL long medTMemberLogin(CVars in, CVars &out)");
    }

    return ret;
}

long MemberSessionCheck(long uid, const char *sessionid, int create) {
    logfmt(logINFO, "long MemberSessionCheck(long uid, const char *sessionid, int create )");
    // Sanity check

    long session_expired_minutes = 15; // load in the global 


    if (uid < 1 || sessionid == NULL || strlen(sessionid) < 4) {
        return -1L; // Invalif parameters
    }
    logfmt(logINFO, "#######-#########-A");
    // Clean old sessions
    if (create == 1) // Clean Previous session by force
    {
        pgsql_exec("DELETE FROM members_session WHERE member_id=%ld", uid);
    }
    logfmt(logINFO, "#######-#########-B");

    pgsql_exec("DELETE FROM members_session WHERE member_id=%ld AND updated < (now() - interval '%lu minutes')", uid, session_expired_minutes);
    // Update/check existing session
    if (create == 0) {

        pgsql_exec("UPDATE members_session SET updated=NOW() WHERE member_id=%ld AND session='%s'", uid, sessionid);

        const PGresult *res = pgsql_query("SELECT * FROM members_session WHERE member_id=%ld AND session='%s'", uid, sessionid);
        if (res != NULL && pgsql_num_rows(res) > 0) {
            logfmt(logINFO, "VALID SESSION *****");
            return 1L; // Session updated
        } else {
            logfmt(logINFO, "INVALID SESSION *****");
            //INVALID SESSION DETECTED
            return -1L; // Invalid parameters
        }

    }

    if (create > 0) {
        // Check session i?
        const PGresult *res = pgsql_query("SELECT * FROM members_session WHERE member_id=%ld AND session<>'%s'", uid, sessionid);
        if (res != NULL && pgsql_num_rows(res) > 0) {
            return -2L; // Active sessions found
        }
        CVars sess; // Do we have the same session already?
        if (load_db_record(sess, "SELECT * FROM members_session WHERE member_id=%lu AND session='%s'", uid, sessionid) > 0) {
            pgsql_exec("UPDATE members_session SET updated=NOW() WHERE member_id=%ld AND session='%s'", uid, sessionid);
            return sess["id"].Long();
        }
        // Create a new session
        const char * loc = getenv("REMOTE_ADDR");
        sess["loc"] = loc;
        sess["loc"].set_valid(true);
        sess["member_id"] = uid;
        sess["member_id"].set_valid(true);
        sess["session"] = sessionid;
        sess["session"].set_valid(true);
        long sid = insert_db_record(DBS_VALID, "members_session", "members_session_id_seq", sess); //members_session_id_seq
        if (sid > 0) {
            return sid; // New session created
        }
        return -3L; // Failed to create new session
    }
    logfmt(logINFO, "/long MemberSessionCheck(long uid, const char *sessionid, int create )");
    return 0L; // No route
}

long CreateMember(CVars in, CVars &out) {
    long ret = PHP_API_BAD_PARAM;
    logfmt(logINFO, "CreateMember()");

    try {

        // REQ_LONG(in, "pid", 0, -1);
        REQ_STRING(in, "username", 5, 49, "(.*)");
        REQ_STRING(in, "firstname", 2, 49, "(.*)");
        REQ_STRING(in, "lastname", 2, 49, "(.*)");
        OPTIONAL(in, "phone") REQ_STRING(in, "phone", 5, 23, "(.*)");
        REQ_STRING(in, "password", 5, 49, "(.*)");
        OPTIONAL(in, "phone") REQ_STRING(in, "loc", 5, 16, "(.*)");
        OPTIONAL(in, "login") REQ_LONG(in, "login", 0, -1);

        long member_id = 0;

        //REQ_STRING (in, "sessionid",  4, 40, "(.*)");
        const char * loc = getenv("REMOTE_ADDR");

        ret = load_db_record(out, "SELECT *,id AS member_id FROM members WHERE LOWER(username)=LOWER('%s') ", in["username"].c_str());
        if (ret > 0) {



            // LETS CREATE THE ACOUNT NOW
            CVars x;

            x["username"] = in["username"];
            x["username"].set_valid(true);
            x["firstname"] = in["firstname"];
            x["firstname"].set_valid(true);
            x["lastname"] = in["lastname"];
            x["lastname"].set_valid(true);
            x["phone"] = in["phone"];
            x["phone"].set_valid(true);
            x["loc"] = in["loc"];
            x["loc"].set_valid(true);
            x["email"] = in["email"];
            x["email"].set_valid(true);
            x["password"] = in["email"];
            x["password"].set_valid(true);
            out["member_id"] = insert_db_record(DBS_VALID, "members", "members_id_seq", x);
            if (out["member_id"].Long() > 0) {
                pgsql_query("UPDATE members SET password = md5('%s') WHERE id  = %lu", in["password"].c_str(), out["member_id"].Long()); // setting the password MD5 now
                // Now Send Email
                ret = PHP_API_OK;
                out["status"] = "OK";
                member_id = out["member_id"].Long();

                //---emailbad    member_email_calls(MERMS_USER_CREATEACCOUNT, out, out);
                // out["member_id"] = member_id;

                //  if (in["login"] != "" && in["login"] == 1) {
                in["action"] = MERMS_USER_LOGIN;
                in["action"].set_valid(true); // needed for next action to know what email to send		
                ret = MemberLogin(in, out);
                ret = 100; // needed if login is good
                // }

                // ==============
            }


        } else {
            // LETS CREATE THE ACOUNT NOW
            CVars x;

            x["username"] = in["username"];
            x["username"].set_valid(true);
            x["firstname"] = in["firstname"];
            x["firstname"].set_valid(true);
            x["lastname"] = in["lastname"];
            x["lastname"].set_valid(true);
            x["phone"] = in["phone"];
            x["phone"].set_valid(true);
            x["loc"] = in["loc"];
            x["loc"].set_valid(true);
            x["email"] = in["email"];
            x["email"].set_valid(true);
            x["password"] = in["email"];
            x["password"].set_valid(true);
            out["member_id"] = insert_db_record(DBS_VALID, "members", "members_id_seq", x);
            if (out["member_id"].Long() > 0) {
                pgsql_query("UPDATE members SET password = md5('%s') WHERE id  = %lu", in["password"].c_str(), out["member_id"].Long()); // setting the password MD5 now
                // Now Send Email
                ret = PHP_API_OK;
                out["status"] = "OK";


                //Email bad      member_email_calls(in["action"].Long(), out, out);

                //  if (in["login"] != "" && in["login"] == 1) {
                in["action"] = MERMS_USER_LOGIN;
                in["action"].set_valid(true); // needed for next action to know what email to send		
                ret = MemberLogin(in, out);
                ret = 100; // needed if login is good
                // }

                // ==============
            }
        }

    } catch (bad_parameter) {
        logfmt(logINFO, "ERROR CALL CreateMember");
    }
    logfmt(logINFO, "/CreateMember()");
    return ret;
}
long getMemberProfile(CVars in, CVars &out);

long MemberProfile(CVars in, CVars &out) {


    try {
        long task_mode = REQ_LONG(in, "task_mode", 0, -1);
        REQ_LONG(in, "member_id", 0, -1);
        switch (task_mode) {
            case MODE_SETVALUE:
                return medTrUpdateProfile(in, out);
                break;

            case MODE_GETVALUE:
                return getMemberProfile(in, out);
                break;
        }
    } catch (bad_parameter) {
        logfmt(logINFO, "ERROR CALL CreateMember");
    }
    logfmt(logINFO, "/MemberReminders()");
    return 0;
}

long getMemberProfile(CVars in, CVars &out) {


    long ret = load_db_record(out, "SELECT m.*,mp.*,m.id AS member_id,mp.id AS member_profile_id FROM members m \
					LEFT JOIN members_profile mp ON mp.member_id = m.id \
					WHERE m.id = %lu", in["member_id"].Long());

    return ret;
}

long medTrUpdateStartProfile(CVars in, CVars &out) {

    long ret = medTrUpdateProfile(in, out);
    if (ret == PHP_API_OK) {
        load_db_record(out, "SELECT UPPER( md5( now()::text) ) AS sessionid,m.*,mp.*,m.id AS member_id,mp.id AS member_profile_id FROM members m \
			            LEFT JOIN members_profile mp ON mp.member_id = m.id \
			            WHERE m.id = %lu", in["member_id"].Long());

        // We need to have the session back
        load_db_record(out, "SELECT * FROM members_session WHERE member_id = %lu ORDER BY id DESC limit 1", in["member_id"].Long());

    }
    return ret;
}

long medTrUpdateProfile(CVars in, CVars &out) {
    long ret = PHP_API_BAD_PARAM;
    logfmt(logINFO, "medTrUpdateProfile()");

    REQ_LONG(in, "member_id", 0, -1);
    REQ_STRING(in, "street1", 2, 49, "(.*)");
    OPTIONAL(in, "street2") REQ_STRING(in, "street2", 1, 49, "(.*)");
    REQ_STRING(in, "city", 5, 49, "(.*)");
    // OPTIONAL(in, "phone") REQ_STRING(in, "phone", 5, 23, "(.*)");
    OPTIONAL(in, "zipcode") REQ_STRING(in, "zipcode", 1, 12, "(.*)");
    REQ_STRING(in, "state", 1, 59, "(.*)");
    REQ_STRING(in, "country", 1, 3, "(.*)");
    REQ_STRING(in, "loc", 5, 16, "(.*)");

    //REQ_STRING (in, "sessionid",  4, 40, "(.*)");
    const char * loc = getenv("REMOTE_ADDR");
    CVars x;
    // x["pid"] = in["pid"];
    // x["pid"].set_valid(true);
    x["street1"] = in["street1"];
    x["street1"].set_valid(true);
    x["street2"] = in["street2"];
    x["street2"].set_valid(true);
    x["city"] = in["city"];
    x["city"].set_valid(true);
    //  x["phone"] = in["phone"];
    // x["phone"].set_valid(true);
    x["zipcode"] = in["zipcode"];
    x["zipcode"].set_valid(true);
    x["loc"] = in["loc"];
    x["loc"].set_valid(true);
    x["state"] = in["state"];
    x["state"].set_valid(true);
    x["country"] = in["country"];
    x["country"].set_valid(true);

    ret = load_db_record(out, "SELECT *,id AS member_profile_id FROM members_profile WHERE member_id = %lu ", in["member_id"].Long());
    if (ret > 0) {
        update_db_record(DBS_VALID, "members_profile", x, in["member_profile_id"].Long());
        member_email_calls(in["action"].Long(), in, out);
        ret = PHP_API_OK;
    } else {
        // LETS CREATE THE ACOUNT NOW
        x["member_id"] = in["member_id"];
        x["member_id"].set_valid(true);
        out["member_profile_id"] = insert_db_record(DBS_VALID, "members_profile", "members_profile_id_seq", x);
        if (out["member_profile_id"].Long() > 0) {
            member_email_calls(in["action"].Long(), in, out);
            // Now Send Email
            ret = PHP_API_OK;
            // ==============
        }
    }
    logfmt(logINFO, "/medTrUpdateProfile()");
    return ret;
}

/*
    "sessionid" => $sessionid, 
        "practice_id" => 0,
        "encounter_id"=> 0,
    "member_id" => "1",
        "description"=> $description,
        "repeat" => $repeat,
        "start_date" => $start_date,
        "end_date" => $end_date,
        "reminder" => rand(0,3)
 */

long setMemberReminders(CVars in, CVars &out);
long getMemberReminders(CVars in, CVars &out);
long delMemberReminders(CVars in, CVars &out);


long MemberReminders(CVars in, CVars &out) {
    try {
        long task_mode = REQ_LONG(in, "task_mode", 0, -1);
        switch (task_mode) {
            case USER_CREATETASK:
                return setMemberReminders(in, out);
                break;

            case USER_LOADTASK:
                return getMemberReminders(in, out);
                break;
						
						case  USER_DELETETASK:
					return delMemberReminders(in, out);			
								break;

        }
    } catch (bad_parameter) {
        logfmt(logINFO, "ERROR CALL CreateMember");
    }
    logfmt(logINFO, "/MemberReminders()");
    return 0;
}

long delMemberReminders(CVars in, CVars &out){


long ret = PHP_API_BAD_PARAM;

    logfmt(logINFO, "delMemberReminders()");

    try {

        REQ_LONG(in, "member_id", 0, -1);
        REQ_LONG(in, "tracked_id", 0, -1);
        REQ_STRING(in, "sessionid", 2, 150, "(.*)");
     
        const char * loc = getenv("REMOTE_ADDR");
 
        pgsql_query("UPDATE members_reminders SET status = 0 WHERE status <> 0 AND member_id = %lu AND id = %lu", in["member_id"].Long(),in["tracked_id"].Long() );
 
        if (ret > 0) {
    
        }

    } catch (bad_parameter) {
        logfmt(logINFO, "ERROR CALL delMemberReminders");
    }
    logfmt(logINFO, "/delMemberReminders()");

return ret;
}

long setMemberReminders(CVars in, CVars &out) {
    long ret = PHP_API_BAD_PARAM;
    logfmt(logINFO, "setMemberReminders()");

    try {
		out = in;
        REQ_LONG(in, "member_id", 0, -1);
        REQ_LONG(in, "practice_id", 0, -1);
        REQ_LONG(in, "encounter_id", 0, -1);
        REQ_STRING(in, "description", 5, 99, "(.*)");
        REQ_LONG(in, "repeat", 0, -1);
        REQ_STRING(in, "start_date", 2, 15, "(.*)");
        REQ_STRING(in, "end_date", 2, 15, "(.*)");
        REQ_LONG(in, "reminder", 0, -1);
        //REQ_STRING (in, "sessionid",  4, 40, "(.*)");
        const char * loc = getenv("REMOTE_ADDR");

        ret = load_db_record(out, "SELECT *,id AS member_id FROM members WHERE id=%lu ", in["member_id"].Long());
        if (ret > 0) {
            // LETS CREATE REMINDER
            CVars x;

            x["member_id"] = in["member_id"];
            x["member_id"].set_valid(true);
            x["practice_id"] = in["practice_id"];
            x["practice_id"].set_valid(true);
            x["encounter_id"] = in["encounter_id"];
            x["encounter_id"].set_valid(true);
            x["description"] = in["description"];
            x["description"].set_valid(true);
            x["loc"] = in["loc"];
            x["loc"].set_valid(true);
            x["repeat"] = in["repeat"];
            x["repeat"].set_valid(true);
            x["reminder"] = in["reminder"];
            x["reminder"].set_valid(true);

            x["start_date"] = in["start_date"];
            x["start_date"].set_valid(true);

            x["end_date"] = in["end_date"];
            x["end_date"].set_valid(true);

            out["member_reminder_id"] = insert_db_record(DBS_VALID, "members_reminders", "members_reminders_id_seq", x);
            if (out["member_reminder_id"].Long() > 0) {
                //---emailbad    member_email_calls(MERMS_USER_CREATEACCOUNT, out, out);	

				
            }
        }

    } catch (bad_parameter) {
        logfmt(logINFO, "ERROR CALL setMemberReminders");
    }
    logfmt(logINFO, "/setMemberReminders()");
    return ret;
}

/*
members_reminders
    "sessionid" => $sessionid, 
        "practice_id" => 0,
        "encounter_id"=> 0,
    "member_id" => "1",
        "description"=> $description,
        "repeat" => $repeat,
        "start_date" => $start_date,
        "end_date" => $end_date,
        "reminder" => rand(0,3)
        status = 1
 */

long getMemberReminders(CVars in, CVars &out) {
    long ret = PHP_API_BAD_PARAM;
    char vname[20];
    try {
        // REQ_LONG(in, "status", 0, -1);
        REQ_LONG(in, "member_id", 0, -1);

        out["total_record"] = "0";

        const PGresult *res = pgsql_query("SELECT *,start_date::date AS start_date_formatted,end_date::date AS end_date_formatted, (CASE WHEN reminder=0 THEN 'Notification' WHEN reminder=1 THEN 'Notification + Email' WHEN reminder=2 THEN 'Email Only' ELSE 'Not Known' END) AS reminder_text  FROM members_reminders WHERE member_id = %lu AND status = 1 ORDER BY start_date ASC", in["member_id"].Long());
        if (res != NULL && pgsql_num_rows(res) > 0) {
            out["total_record"] = pgsql_num_rows(res);

            for (int i = 0, n = pgsql_num_rows(res); i < n; i++) {
                map<const char*, const char*>f = pgsql_fetch_assoc(res, i);
                if (f.empty()) continue;
                CVars rec;
                map_to_cvars(f, rec);

                snprintf(vname, sizeof (vname), "id_%05d", i);
                out[vname] = rec["id"];


                snprintf(vname, sizeof (vname), "description_%05d", i);
                out[vname] = rec["description"];

                snprintf(vname, sizeof (vname), "repeat_%05d", i);
                out[vname] = rec["repeat"];

                snprintf(vname, sizeof (vname), "start_date_%05d", i);
                out[vname] = rec["start_date_formatted"];

                snprintf(vname, sizeof (vname), "end_date_%05d", i);
                out[vname] = rec["end_date_formatted"];

                snprintf(vname, sizeof (vname), "reminder_%05d", i);
                out[vname] = rec["reminder"];

				snprintf(vname, sizeof (vname), "reminder_text_%05d", i);
                out[vname] = rec["reminder_text"];
				
                snprintf(vname, sizeof (vname), "status_%05d", i);
                out[vname] = rec["status"];

            }
        }
        ret = PHP_API_OK;
        out["status"] = "OK";
    } catch (bad_parameter) {
        logfmt(logINFO, "ERROR CALL long getMemberReminders(CVars in, CVars &out)");
    }
    return ret;
}

/*
mermsemr_dev=> select p.id AS partient_id,p.added AS patient_added,p.long_id AS long_id, pra.* from patients p LEFT JOIN practice pra ON pra.id=p.practice_id WHERE p.member_id=3;
 partient_id |       patient_added        |   long_id   | id |           name            | firstname | lastname |          email           |   phone    | username |             password             |           added           |   loc    | last_login | status 
-------------+----------------------------+-------------+----+---------------------------+-----------+----------+--------------------------+------------+----------+----------------------------------+---------------------------+----------+------------+--------
           3 | 2019-03-11 14:31:54.207198 | INT00000003 |  1 | University Hospital Space | Sanya     | Ameye    | ses66181+merms@gmail.com | 6784564356 | sameye   | d0fbea2563b377ea7074bced45c88dcb | 2019-03-03 21:35:51.48451 | 10.0.0.1 |            |      1
(1 row)

*/

long getMemberPractice(CVars in, CVars &out) {
    long ret = PHP_API_BAD_PARAM;
    char vname[20];
    try {
        // REQ_LONG(in, "status", 0, -1);
        REQ_LONG(in, "member_id", 0, -1);

        out["total_record"] = "0";

        const PGresult *res = pgsql_query("SELECT p.id AS patient_id,p.status AS patient_status, pra.* FROM patients p LEFT JOIN practice pra ON pra.id=p.practice_id WHERE p.member_id = %lu", in["member_id"].Long());
        
        if (res != NULL && pgsql_num_rows(res) > 0) {
            out["total_record"] = pgsql_num_rows(res);

            for (int i = 0, n = pgsql_num_rows(res); i < n; i++) {
                map<const char*, const char*>f = pgsql_fetch_assoc(res, i);
                if (f.empty()) continue;
                CVars rec;
                map_to_cvars(f, rec);

                snprintf(vname, sizeof (vname), "id_%05d", i);
                out[vname] = rec["id"];


                snprintf(vname, sizeof (vname), "patient_id_%05d", i);
                out[vname] = rec["patient_id"];

                snprintf(vname, sizeof (vname), "name_%05d", i);
                out[vname] = rec["name"];

                snprintf(vname, sizeof (vname), "long_id_%05d", i);
                out[vname] = rec["long_id"];

                snprintf(vname, sizeof (vname), "patient_added_%05d", i);
                out[vname] = rec["added"];

                snprintf(vname, sizeof (vname), "added_by_%05d", i);
                out[vname] = "Self";

                
                snprintf(vname, sizeof (vname), "patient_status_%05d", i);
                out[vname] = rec["patient_status"];

            }
        }
        ret = PHP_API_OK;
        out["status"] = "OK";
    } catch (bad_parameter) {
        logfmt(logINFO, "ERROR CALL long getMemberPractice(CVars in, CVars &out)");
    }
    return ret;
}

//------------------------------------------------------

long serviceCost(long service_id, long discount_rate);

long medTrMemberTransportById(CVars in, CVars &out) {
    long ret = PHP_API_BAD_PARAM;
    ret = load_db_record(out, "SELECT * FROM members_service_request WHERE id = %lu ", in["transport_id"].Long());
    if (ret > 0) {
        ret = PHP_API_OK;
    }
    return ret;
}

long DeletAallCards(CVars in, CVars &out) {
    long ret = PHP_API_BAD_PARAM;
    out["status"] = "Pending";
    try {
        REQ_LONG(in, "member_id", 0, -1);
        pgsql_query("UPDATE creditcard SET status = 7,active = 0 WHERE status <> 7 AND member_id = %lu", in["member_id"].Long());
        pgsql_query("UPDATE members SET stripe_customer_id = NULL,def_card = NULL WHERE id  = %lu", in["member_id"].Long());
        ret = PHP_API_OK;
        out["status"] = "Completed";

    } catch (bad_parameter) {
        out["status"] = "Error";

        logfmt(logINFO, "ERROR CALL long DeletAallCards(CVars in, CVars &out)");
    }
    return ret;
}

long medTrMemberServiceById(CVars in, CVars &out) {
    long ret = PHP_API_BAD_PARAM;

    logfmt(logINFO, " CALL long medTrMemberServiceById(CVars in, CVars &out)");
    try {
        REQ_LONG(in, "member_id", 0, -1);
        REQ_LONG(in, "service_id", 0, -1);

        ret = load_db_record(out, "SELECT s.service_date,s.quantity,a.agent_name,s.est_cost AS estimated_cost,s.flags,s.status,"
                " TO_CHAR(s.service_date :: TIMESTAMP, 'Day Mon dd, yyyy HH:MM AM') AS long_date,"
                " a.street,a.city,a.zipcode,a.phone,a.state, "
                " (CASE WHEN s.dt_confirmed IS NOT NULL THEN 'Confirmed' ELSE 'Not Confirmed' END) AS confirm_text,s.id AS service_id "
                " FROM members_service_request s "
                " LEFT JOIN agents a ON a.id = s.agent_id "
                " WHERE s.id = %lu ", in["service_id"].Long());
        if (ret > 0) {
            //  out["estimated_cost"] ="34.00";

            getServiceDetail(out["service_id"].Long(), out);

            //  snprintf(vname, sizeof (vname), "service_list_detail_%05d", i);
            //  out[vname] = out["service_list"];

            ret = PHP_API_OK;
        }

        ret = PHP_API_OK;
        out["status"] = "OK";
    } catch (bad_parameter) {
        logfmt(logINFO, "ERROR CALL long medTrMemberServiceById(CVars in, CVars &out)");
    }
    return ret;
}

long medTrLanguageList(CVars in, CVars &out) {
    long ret = PHP_API_BAD_PARAM;
    char vname[20];
    try {
        // REQ_LONG(in, "status", 0, -1);
        REQ_LONG(in, "member_id", 0, -1);

        out["total_record"] = "0";

        const PGresult *res = pgsql_query("SELECT * FROM agents WHERE status = 1 ORDER BY agent_name ASC");
        if (res != NULL && pgsql_num_rows(res) > 0) {
            out["total_record"] = pgsql_num_rows(res);

            for (int i = 0, n = pgsql_num_rows(res); i < n; i++) {
                map<const char*, const char*>f = pgsql_fetch_assoc(res, i);
                if (f.empty()) continue;
                CVars rec;
                map_to_cvars(f, rec);

                snprintf(vname, sizeof (vname), "agent_name_%05d", i);
                out[vname] = rec["agent_name"];

                snprintf(vname, sizeof (vname), "agent_id_%05d", i);
                out[vname] = rec["id"];

                snprintf(vname, sizeof (vname), "street_%05d", i);
                out[vname] = rec["street"];

                snprintf(vname, sizeof (vname), "city_%05d", i);
                out[vname] = rec["city"];

                snprintf(vname, sizeof (vname), "zipcode_%05d", i);
                out[vname] = rec["zipcode"];

            }
        }
        ret = PHP_API_OK;
        out["status"] = "OK";
    } catch (bad_parameter) {
        logfmt(logINFO, "ERROR CALL long medTMemberLogin(CVars in, CVars &out)");
    }
    return ret;
}

/*
 * street          |   city   | zipcode
 kleen=> SELECT t.*,a.agent_name,TO_CHAR(t.service_date :: TIMESTAMP, 'Day Mon dd, yyyy HH:MM AM') AS long_date  FROM members_service_request t LEFT JOIN agents a ON a.id=t.agent_id;
 id | pid | member_id | agent_id | service_type |    service_date     | quantity |           added            | status | flags |       loc       | dist_mode | miles | minutes |         agent_name         |            long_date            
----+-----+-----------+----------+--------------+---------------------+----------+----------------------------+--------+-------+-----------------+-----------+-------+---------+----------------------------+---------------------------------
  3 | 100 |         1 |        3 |            1 | 2018-05-12 23:05:00 |        3 | 2018-05-12 23:05:34.962922 |      1 |     1 | 104.238.127.115 |           |     0 |       0 | Agenr Name with name 10003 | Saturday  May 12, 2018 11:05 PM

 */

long medTrMemberTransportList(CVars in, CVars &out) {
    logfmt(FLOG_MAX, "long medTrMemberTransportList(CVars in, CVars &out)");
    long ret = PHP_API_BAD_PARAM;
    char vname[30];
    try {
        REQ_LONG(in, "limit", 0, -1);
        REQ_LONG(in, "member_id", 0, -1);

        out["total_record"] = "0";

        const PGresult *res = pgsql_query("SELECT t.id AS service_id, t.*,a.agent_name,"
                " TO_CHAR(t.service_date :: TIMESTAMP, 'Day Mon dd, yyyy HH:MM AM') AS long_date , "
                " (CASE WHEN t.dt_confirmed IS NOT NULL THEN 'Confirmed' ELSE 'Not Confirmed' END) AS confirm_text,"
                " (CASE WHEN t.flags IN(0,1) THEN 'Not Confirmed' WHEN t.flags=2 THEN 'Confirmed' WHEN t.flags=4 THEN 'Assigned' ELSE  'Unknown' END) AS flag_text,"
                " (CASE WHEN t.service_type=1 THEN 'Laundry' WHEN t.service_type=2 THEN 'Dryclean' ELSE 'Service' END) AS service_type_description"
                " FROM members_service_request t LEFT JOIN agents a ON a.id=t.agent_id "
                " WHERE t.member_id= %lu "
                " ORDER BY t.id DESC LIMIT %lu", in["member_id"].Long(), in["limit"].Long());

        if (res != NULL && pgsql_num_rows(res) > 0) {
            out["total_record"] = pgsql_num_rows(res);

            for (int i = 0, n = pgsql_num_rows(res); i < n; i++) {
                map<const char*, const char*>f = pgsql_fetch_assoc(res, i);
                if (f.empty()) continue;
                CVars rec;
                map_to_cvars(f, rec);

                long service_id = rec["service_id"].Long();

                snprintf(vname, sizeof (vname), "service_date_%05d", i);
                out[vname] = rec["service_date"];

                snprintf(vname, sizeof (vname), "long_date_%05d", i);
                out[vname] = rec["long_date"];

                snprintf(vname, sizeof (vname), "service_id_%05d", i);
                out[vname] = rec["service_id"];

                snprintf(vname, sizeof (vname), "agent_name_%05d", i);
                out[vname] = rec["agent_name"];

                snprintf(vname, sizeof (vname), "status_%05d", i);
                out[vname] = rec["status"];

                snprintf(vname, sizeof (vname), "flags_%05d", i);
                out[vname] = rec["flags"];

                snprintf(vname, sizeof (vname), "from_city_%05d", i);
                out[vname] = rec["from_city"];

                snprintf(vname, sizeof (vname), "quantity_%05d", i);
                out[vname] = rec["quantity"];

                snprintf(vname, sizeof (vname), "confirm_text_%05d", i);
                out[vname] = rec["confirm_text"];

                snprintf(vname, sizeof (vname), "service_fee_%05d", i);
                out[vname] = "0";

                snprintf(vname, sizeof (vname), "stype_desc_%05d", i);
                out[vname] = rec["service_type_description"];

                getServiceDetail(service_id, out);

                snprintf(vname, sizeof (vname), "service_list_detail_%05d", i);
                out[vname] = out["service_list"];





                snprintf(vname, sizeof (vname), "flag_text_%05d", i);
                out[vname] = rec["flag_text"];
            }
        }
        ret = PHP_API_OK;
        out["status"] = "OK";
    } catch (bad_parameter) {
        logfmt(logINFO, "ERROR CALL long medTMemberLogin(CVars in, CVars &out)");
    }
    logfmt(FLOG_MAX, "/long medTrMemberTransportList(CVars in, CVars &out)");
    return ret;
}

long getServiceDetail(long service_id, CVars &out) {
    out["service_list"] = "";
    char vname[300];
    long ret = 0;
    int icc = 0;
    ret = load_db_record(out, "SELECT * FROM members_service_request  WHERE id = %lu ", service_id);
    if (ret > 0) {

        switch (out["service_type"].Long()) {
            case 1:
                snprintf(vname, sizeof (vname), "%lu Bag(s)", out["quantity"].Long());
                out["service_list"] = vname;
                out["total_detail_record"] = "1";
                break;

            case 2:

                const PGresult *res = pgsql_query(" SELECT code,description,price*0.01 AS price,quantity,total*0.01 AS total "
                        " FROM members_service_detail "
                        " WHERE service_id=%lu", service_id);

                if (res != NULL && pgsql_num_rows(res) > 0) {
                    out["total_detail_record"] = pgsql_num_rows(res);
                    snprintf(vname, sizeof (vname), ""); // clean it up
                    for (int i = 0, n = pgsql_num_rows(res); i < n; i++) {
                        map<const char*, const char*>f = pgsql_fetch_assoc(res, i);
                        if (f.empty()) continue;
                        CVars rec;
                        map_to_cvars(f, rec);
                        out["lv"] = vname;
                        if (icc > 0) {
                            snprintf(vname, sizeof (vname), "%s, ", out["lv"].c_str());
                        }
                        out["lv"] = vname;
                        snprintf(vname, sizeof (vname), "%s %lu %s", out["lv"].c_str(), rec["quantity"].Long(), rec["description"].c_str());

                        icc++;
                    }
                    out["service_list"] = vname;

                }

                break;
        }
    }
    return 0;
}

vector<string> split_string(const char *str, char c = ' ') {
    vector<string> result;
    do {
        const char *begin = str;
        while (*str != c && *str)
            str++;
        result.push_back(string(begin, str));
    } while (0 != *str++);
    return result;
}

// trim from start (in place)

static inline void ltrim(std::string &s) {
    s.erase(s.begin(), std::find_if(s.begin(), s.end(),
            std::not1(std::ptr_fun<int, int>(std::isspace))));
}

// trim from end (in place)

static inline void rtrim(std::string &s) {
    s.erase(std::find_if(s.rbegin(), s.rend(),
            std::not1(std::ptr_fun<int, int>(std::isspace))).base(), s.end());
}

// trim from both ends (in place)

static inline void trim(std::string &s) {
    ltrim(s);
    rtrim(s);
}

// trim from start (copying)

static inline std::string ltrim_copy(std::string s) {
    ltrim(s);
    return s;
}

// trim from end (copying)

static inline std::string rtrim_copy(std::string s) {
    rtrim(s);
    return s;
}

// trim from both ends (copying)

static inline std::string trim_copy(std::string s) {
    trim(s);
    return s;
}

long kleenNewLundryPickUp(CVars in, CVars &out) {
    CVars k;
    out = in;

    long ret = PHP_API_BAD_PARAM;
    long service_total = 0;
    long discount_rate = 0;
    try {

        logfmt(logINFO, "kleenNewLundryPickUp Start()");
        REQ_LONG(in, "pid", 0, -1);
        REQ_LONG(in, "member_id", 0, -1);
        REQ_LONG(in, "service_type", 0, -1);
        REQ_LONG(in, "agent_id", 0, -1);
        REQ_STRING(in, "service_date", 5, 23, "(.*)");
        REQ_LONG(in, "quantity", 0, -1);
        REQ_LONG(in, "deliverydays", 0, -1);
        REQ_STRING(in, "deiverytime", 5, 11, "(.*)");
        REQ_STRING(in, "service_list", 1, 120, "(.*)");
        REQ_STRING(in, "loc", 5, 16, "(.*)");
        OPTIONAL(in, "instruction") REQ_STRING(in, "instruction", 1, 100, "(.*)");
        //REQ_STRING (in, "sessionid",  4, 40, "(.*)");
        OPTIONAL(in, "coupon") REQ_STRING(in, "coupon", 1, 15, "(.*)");
        OPTIONAL(in, "discount_rate") REQ_LONG(in, "discount_rate", 0, -1);

        discount_rate = in["discount_rate"].Long() + 0;

        const char * loc = getenv("REMOTE_ADDR");

        long memberF = 0;
        logfmt(logINFO, "~~~~~SPLIT_IN1~~~~ MEMBER %lu", memberF);
        memberF = load_db_record(k, "SELECT *,id AS member_id FROM members WHERE id=%lu ", in["member_id"].Long());
        logfmt(logINFO, "~~~~~SPLIT_IN2~~~~ MEMBER %lu", memberF);
        // memberF = 1;
        if (memberF > 0) {
            // LETS CREATE THE REQUEST NOW
            CVars x;
            x["pid"] = in["pid"];
            x["pid"].set_valid(true);

            x["service_type"] = in["service_type"];
            x["service_type"].set_valid(true);

            x["member_id"] = in["member_id"];
            x["member_id"].set_valid(true);
            x["agent_id"] = in["agent_id"];
            x["agent_id"].set_valid(true);
            x["service_type"] = in["service_type"];
            x["service_type"].set_valid(true);
            x["service_date"] = in["service_date"];
            x["service_date"].set_valid(true);
            x["loc"] = loc;
            x["loc"].set_valid(true);
            x["quantity"] = in["quantity"];
            x["quantity"].set_valid(true);

            x["deliverydays"] = in["deliverydays"];
            x["deliverydays"].set_valid(true);
            x["deiverytime"] = in["deiverytime"];
            x["deiverytime"].set_valid(true);

            x["coupon"] = in["coupon"];
            x["coupon"].set_valid(true);

            //in["service_list"] = " S01-1@S02-1@S03-1@S04-1@S05-1@S06-4@S07-1@S08-1@S09-1@S10-1@ ";
            /*
             I want to spilit int   
			 
             S01  1
             S02  2
             S03  1
             S04  1
             S05  1
             S06  2
             S07  1
             S08  1
             S09  1
             S10  1
			 
             INSERT INTO table (SO1, 1)
             */




            out["service_id"] = insert_db_record(DBS_VALID, "members_service_request", "members_service_request_id_seq", x);
            if (out["service_id"].Long() > 0) {

                if (in["instruction"].length() > 0) {
                    // let us save instruction to  another table
                }

                if (x["service_type"].Long() == 2) { // dry clean service now
                    logfmt(FLOG_MAX, "service_list=%s", in["service_list"].c_str());
                    vector<string> result = split_string(in["service_list"].c_str(), '@');
                    vector<string>::iterator it;
                    char *key, *val;
                    for (it = result.begin(); it != result.end(); it++) {
                        string item = trim_copy(*it);
                        if (item.empty()) {
                            logfmt(FLOG_MAX, "item is empty");
                        } else {
                            logfmt(FLOG_MAX, "item=%s", item.c_str());
                            key = strtok((char *) item.c_str(), "-");
                            val = strtok(NULL, "-");
                            logfmt(FLOG_MAX, "key=%s, val=%s", key, val);

                            CVars v;
                            if (load_db_record(v, "SELECT * FROM dryclean_service WHERE code='%s' ", key) > 0) {
                                CVars m;
                                m["member_id"] = in["member_id"];
                                m["member_id"].set_valid(true);
                                m["service_id"] = out["service_id"];
                                m["service_id"].set_valid(true);
                                m["code"] = v["code"];
                                m["code"].set_valid(true);
                                m["description"] = v["description"];
                                m["description"].set_valid(true);
                                m["price"] = v["price"];
                                m["price"].set_valid(true);
                                m["quantity"] = val;
                                m["quantity"].set_valid(true);
                                m["total"] = m["quantity"].Long() * v["price"].Long();
                                m["total"].set_valid(true);
                                out["detail_id"] = insert_db_record(DBS_VALID, "members_service_detail", "members_service_detail_id_seq", m);

                                service_total = m["total"].Long() + service_total;

                                /*
                                  id | code |    description    | price |           added            
                                ----+------+-------------------+-------+----------------------------
                                  1 | S01  | Shirt (Laundry)   |   160 | 2018-07-19 09:43:21.379297
                                  2 | S02  | Shirt (Dry Clean) |   400 | 2018-07-19 09:43:21.383512
                                  3 | S03  | Shirt (Ladies)    |   400 | 2018-07-19 09:43:21.386951

                                 */

                            }
                        }
                    }


                }



                CVars t;
                if (in["service_type"].Long() == 2) {

                    if (discount_rate < 100) {
                        service_total = service_total * (100 - discount_rate) / 100;
                    }
                    t["est_cost"] = service_total;
                } else {
                    t["est_cost"] = serviceCost(out["service_id"].Long(), discount_rate);
                }

                pgsql_query("UPDATE members_service_request SET est_cost =  %lu, discount_rate = %lu WHERE id = %lu", t["est_cost"].Long(), discount_rate, out["service_id"].Long());

                serviceCost(out["service_id"].Long(), discount_rate);
                load_db_record(out, "SELECT * FROM members_service_request WHERE id=%lu ", out["service_id"].Long());
                // Now Send Email
                member_email_calls(in["action"].Long(), out, out);
                alert_email_calls(in["action"].Long(), out, out);
                // ==============
                ret = 100;

            }

        } else {

        }

    } catch (bad_parameter) {
        logfmt(logINFO, "ERROR CALL long kleenNewLundryPickUp(CVars in, CVars &out)");
    }

    logfmt(logINFO, "/kleenNewLundryPickUp()");
    return ret;

}

long serviceCost(long service_id, long discount_rate) {
    long service_cost = 0;
    CVars k;
    if (load_db_record(k, "SELECT * FROM members_service_request WHERE id=%lu ", service_id) > 0) {
        if (k["deliverydays"].Long() == 1) {
            service_cost = (k["quantity"].Long() * 3000 + 1000)*(1.10) *1.03;
        } else {
            service_cost = (k["quantity"].Long() * 3000 + 1000) *1.03;

        }

    }
    if (discount_rate < 100) {
        service_cost = service_cost * (100 - discount_rate) / 100;
    }
    return service_cost;
}

// vi:ts=2

