// Account management toosl
#include "clog.h"
#include "cgi.h"
#include "input.h"
#include "wrenchboard_api.h"
#include "account.h"
#include "email.h"
#include "safestring.h"
#include <string>
#include "pgsql.h"
#include "pgsql_wrapper.h"
#include "cfg.h"
#include <curl/curl.h>
#include "smoney.h"
#include "account_mngt.h"
#include "creditcards.h"
#include "payments.h"

#include "sel_data.h"
#include "history.h"
#include "recent_data.h";

#include "jobs.h"
#include "reco_engine.h"  //error in file name

#define CREATE_BY_EMAIL 1000
#define CREATE_BY_PHONE 2000

struct MemoryStruct {
    char *memory;
    size_t size;
};

static size_t
WriteMemoryCallback(void *contents, size_t size, size_t nmemb, void *userp) {
    size_t realsize = size * nmemb;
    struct MemoryStruct *mem = (struct MemoryStruct *) userp;

    mem->memory = (char*) realloc(mem->memory, mem->size + realsize + 1);
    if (mem->memory == NULL) {
        /* out of memory! */
        logfmt(logINFO, "not enough memory (realloc returned NULL)");
        return 0;
    }

    memcpy(&(mem->memory[mem->size]), contents, realsize);
    mem->size += realsize;
    mem->memory[mem->size] = 0;

    return realsize;
}

static const string base64_chars =
        "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
        "abcdefghijklmnopqrstuvwxyz"
        "0123456789+/";

static inline bool is_base64(unsigned char c) {
    return (isalnum(c) || (c == '+') || (c == '/'));
}


string base64_decode(string const& encoded_string) {
    int in_len = encoded_string.size();
    int i = 0;
    int j = 0;
    int in_ = 0;

    unsigned char char_array_4[4], char_array_3[3];
    std::string ret;

    while (in_len-- && (encoded_string[in_] != '=') && is_base64(encoded_string[in_])) {
        char_array_4[i++] = encoded_string[in_];
        in_++;
        if (i == 4) {
            for (i = 0; i < 4; i++)
                char_array_4[i] = base64_chars.find(char_array_4[i]);

            char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
            char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
            char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];

            for (i = 0; (i < 3); i++)
                ret += char_array_3[i];
            i = 0;
        }
    }

    if (i) {
        for (j = i; j < 4; j++)
            char_array_4[j] = 0;

        for (j = 0; j < 4; j++)
            char_array_4[j] = base64_chars.find(char_array_4[j]);

        char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
        char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
        char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];

        for (j = 0; (j < i - 1); j++) ret += char_array_3[j];
    }

    return ret;
}

/*
CREATE TABLE members_log (
id SERIAL,
member_id INT REFERENCES members(id),
mlog TEXT,
loc INET,
status INT DEFAULT 1,		
created timestamp without time zone DEFAULT now()
);
 */


long test() {
         FILE* oldFile = Output2FILE::Stream();
             FILE* pFile = fopen(WRENCHBOARD_CONFIG"/../logs/somefile.log", "a");
                 Output2FILE::Stream() = pFile;
                 //...
                     FILE_LOG(logINFO) << "Some text...";
                         logfmt(logINFO, "Some text...");
                         //...
                             fclose(pFile);
                                 Output2FILE::Stream() = oldFile;
                                 return 0L;
}
long WrenchTestWalletCapability(CVars in, CVars &out);
long WrenchImportContacts(CVars in, CVars &out);
long WrenchRequestVirtualCard(CVars in, CVars &out);
long WrenchRequestFamilyVirtualCard(CVars in, CVars &out);
long WrenchLoadReferLink(CVars in, CVars &out);

long account_calls(CVars in, CVars &out) {
    logfmt(logINFO, "account_calls()");
    out["result"] = "YES I GET TO BACK END";
    long action = REQ_LONG(in, "action", 0, -1);
    CVars x;
    long ret = 0;
    const char * loc = getenv("REMOTE_ADDR");
    const PGresult *res;
    logfmt(logINFO, "action = %ld", action);
    logfmt(logINFO, "google = %ld", WRENCHBOARD_GOOGLE_LOGIN);
   //test();

    switch (action) {
        case WRENCHBOARD_CREATE_MOBILEUSER:
            return CreateMobileWrenchBoardAccount(in, out);
            break;

        case WRENCHBOARD_COMPLETE_MOBILEUSER:
            return CompleteMobileAccountCreation(in, out);
            break;

        case WRENCHBOARD_RESET_PASSWORD:
            return WrenchResetMemberPass(in, out);
            break;

        case WRENCHBOARD_MOBILE_MESSAGE:
           // return WrenchReturnMemberMessages(in, out);
            return WrenchMemberMarketMessages(in, out);
            break;


        case WRENCHBOARD_MOBILE_JOB_MESSAGE:
            return WrenchMemberOwnerMarketMessages(in, out);
            break;


        case WRENCHBOARD_MOBILE_ACTIVEJOB:
            return WrenchMemberActiveJobs(in, out);
            break;
            
        case WRENCHBOARD_ACCOUNT_TESTEMAIL:

            break;




        case WRENCHBOARD_SAVE_GALLERY:
            return WrenchUpdateSiteGallery(in, out);
            break;



        case WRENCHBOARD_SEND_CONTACTUS:
            logfmt(logINFO, "ContactUS()");
            REQ_STRING(in, "email", 5, 49, "(.*)");
            REQ_STRING(in, "firstname", 1, 49, "(.*)");
            REQ_STRING(in, "lastname", 1, 40, "(.*)");
						REQ_STRING(in, "your_message", 4, 400, "(.*)");
            //OPTIONAL( in, "loc" ) REQ_STRING (in, "loc",   3, 15, "(.*)");

            in["loc"] = loc;
            in["loc"].set_valid(true);

            x["firstname"] = in["firstname"];
            x["firstname"].set_valid(true);
            x["lastname"] = in["lastname"];
            x["lastname"].set_valid(true);
            x["email"] = in["email"];
            x["email"].set_valid(true);
            x["your_message"] = in["your_message"];
            x["your_message"].set_valid(true);
            if (in["loc"].length() > 0) x["loc"] = in["loc"];
            x["loc"].set_valid(true);


            ret = insert_db_record(DBS_VALID, "contacts", "contacts_id_seq", x);
            if (ret > 0) {
                x["contact_id"] = ret;
                x["contact_id"].set_valid(true);
                //ContactMessage(x);  RETIRED
                account_email(ACCOUNT_CONTACT_ALERT, x, out);
            }
            break;

        case WRENCHBOARD_ACCOUNT_QRLOGIN:
            return LoginWrenchBoardQRAccount(in, out);
            break;

        case WRENCHBOARD_ACCOUNT_LOGIN:
            return LoginWrenchBoardAccount(in, out);
            break;

        case WRENCHBOARD_PROMO_LOGIN:
            return LoginWrenchPromoAccount( in, out );
        break;

        case WRENCHBOARD_ACCOUNT_AUXLOGIN:
            return LoginWrenchBoardAuxAccount(in, out);
        break;

        case WRENCHBOARD_FACEBOOK_LOGIN:
            return LoginWrenchBoardFacebook(in, out);
            break;

        case WRENCHBOARD_GOOGLE_LOGIN:
            return LoginWrenchBoardGoogle(in, out);
            break;

        case WRENCHBOARD_APPLE_LOGIN:
            return LoginWrenchBoardApple(in, out);
            break;

        case WRENCHBOARD_ACCOUNT_PENDING:
            return CreateWrenchBoardAccountPending(in, out);
            break;

        case WRENCHBOARD_ACCOUNT_CREATEACC:
            return CreateWrenchBoardAccount(in, out);
            break;

        case WRENCHBOARD_LOG_MEMBER:
            return LogWrenchBoardMember(in, out);
            break;

        case WRENCHBOARD_ACCOUNT_RESETPASS:
            return WrenchResetMemberPass(in, out);
            break;

        case WRENCHBOARD_RESEND_PENDING_LINK:
            REQ_LONG(in, "pending_id", 1, -1);
            account_email(ACCOUNT_RESEND_PENDING, in, out); // ALERT CUSTOMER OF LOGIN
            break;

        case WRENCHBOARD_DELETE_PENDING_LINK:
            REQ_LONG(in, "pending_id", 1, -1);
            pgsql_exec("UPDATE members_pending SET status=7,username='DEL-%lu' WHERE id=%lu AND status = 1", in["pending_id"].Long(), in["pending_id"].Long());
            break;

        case WRENCHBOARD_ACCOUNT_SENDREFER:
            return WrenchSendRefer(in, out);
            break;

        case WRENCHBOARD_ACCOUNT_REFERLINK:
            return WrenchSendReferLoadLink(in, out);
            break;
			
		case WRENCHBOARD_ACCOUNT_REFRESENDLNK:
		    return WrenchResendSendReferLoadLink(in, out);
		break;
			
        case WRENCHBOARD_SESSION_VERIFY:
            return VerifySession(in, out);
            break;

        case WRENCHBOARD_UPDATE_PROFILE:
            return WrenchUpdateProfile(in, out);
            break;

        case WRENCHBOARD_ACCOUNT_TERMS:
            return WrenchUpdateAccountTerms(in, out);
            break;

        case WRENCHBOARD_ACCOUNT_MDESCRIPTION:
            return WrenchUpdateAccountDescription(in, out);
            break;

        case WRENCHBOARD_ACCOUNT_SETPASSWD:
            return WrenchResetPass(in, out);
            break;

        case WRENCHBOARD_ACCOUNT_SAVESKILL:
            return WrenchSaveSkill(in, out);
            break;

        case WRENCHBOARD_ACCOUNT_DELSKILL:
            return WrenchDeleteSaveSkill(in, out);
            break;

        case WRENCHBOARD_DELETE_RECACC:
            REQ_LONG(in, "recipient_id", 1, -1);
            REQ_LONG(in, "member_id", 1, -1);
            if (pgsql_exec("UPDATE sendmoney_recipient SET status=7 WHERE member_id=%lu  AND  id=%lu AND status = 1", in["member_id"].Long(), in["recipient_id"].Long())) {
                ret = PHP_API_OK;
            }
            break;

//        case WRENCHBOARD_START_JOBLIST:
//            return WrenchReturnStartJobList(in, out);
//            break;
//
        case WRENCHBOARD_START_JOBLIST:
        case WRENCHBOARD_ACCOUNT_JOBLIST:
           return  WrenchReturnJobList(in, out);
            break;
            
        case WRENCHBOARD_ACCOUNT_PENDJOB: // user pending job
            return WrenchReturnPendingJobList(in, out);
            break;

        case WRENCHBOARD_ACCT_NOTIFICATIONS:
           return WrenchReturnMemberNotifications(in, out);
        break;

        case WRENCHBOARD_ACCT_HELPITEMS:
            return WrenchReturnHelpItems( in, out);
        break;

        case WRENCHBOARD_ACCOUNT_DASHDATA:
            return WrenchLoadDashData(in, out);
            break;

        case WRENCHBOARD_USER_GETBANKLIST:  
                return WrenchReturnMemberBankAccount(in, out);
                break;       

        case WRENCHBOARD_USER_SENDMONEY:   
                return   WrenchBoardMobileSendMoney(in, out);
                break;      

        case WRENCHBOARD_USER_SENDJOBINT:  
               return   WrenchBoardMobileSendJobInterest(in, out);
               break;
        case WRECNH_CREDIT_HOOKS_FULUTTER:
                 return  WrenchFlutterCreditHook(in, out);
               break;
        case WRENCHBOARD_USER_STARTCREDIT:
                return WrenchStartPayment(in, out);
                break;
        case WRENCHBOARD_USER_ADNEWCC:       
                return WrenchNewCardPayment(in, out);
                break;
        case WRENCHBOARD_USER_CARDLIST:
                return WrenchUsersCCardList(in, out);
                break;
        case  WRENCHBOARD_USER_CARDREMV:
                 return WrenchDeleteUsersCCard(in, out);
                break;
        case WRENCHBOARD_USER_USESAVEDCC:
               return WrenchCardRechargePayment(in, out);
               break;

         case WRENCHBOARD_GETUSER_SETTINGS:
               return WrenchAccountSettings(in, out);
               break;

        case WRENCHBOARD_USER_SETTINGS:
               REQ_LONG(in, "member_id", 1, -1);
               REQ_STRING(in, "uid", 3, 150, "(.*)");
               REQ_STRING(in, "pref_id", 4, 6, "(.*)");
               REQ_LONG(in, "status", 1, -1);

                res = pgsql_query("SELECT id FROM members_settings WHERE member_id=%lu  AND  pref_id='%s' ", in["member_id"].Long(), in["pref_id"].c_str());
                if (res != NULL && pgsql_num_rows(res) > 0) {
                     pgsql_exec("UPDATE members_settings SET status=%lu WHERE member_id=%lu  AND  pref_id='%s' ",in["status"].Long(), in["member_id"].Long(), in["pref_id"].c_str());
                     out["status"] = "completed";
                }
                else{
                    CVars xx;
                    xx["member_id"] = in["member_id"]; xx["member_id"].set_valid(true);
                    xx["pref_id"]   = in["pref_id"];   xx["pref_id"].set_valid(true);
                    xx["status"]    = in["status"];    xx["status"].set_valid(true);
                    insert_db_record(DBS_VALID, "members_settings", "members_settings_id_seq", xx);
                    out["status"] = "completed";
                }
                ret = PHP_API_OK;
               break;

        case WRENCHBOARD_ACCOUNT_WALLETS:
                  logfmt(logINFO, "/WRENCHBOARD_ACCOUNT_WALLETS()");
                  return WrenchBoardMobileSendUserWallet(in, out);
               break;

        case WRENCHBOARD_ACCOUNT_TOPUP_RESULT:
                logfmt(logINFO, "/WRENCHBOARD_ACCOUNT_TOPUP_RESULT()");
                //return WrenchBoardStartBalanceTopup(in, out);
                return WrenchBoardTopupResult(in, out);
        break;

        case WRENCHBOARD_ACCOUNT_PREPARE_TOPUP:
                  logfmt(logINFO, "/WRENCHBOARD_ACCOUNT_PREPARE_TOPUP()");
                  return WrenchBoardStartBalanceTopup(in, out);
               break;

        case WRENCHBOARD_ACCOUNT_COMPLETE_TOPUP:
                  logfmt(logINFO, "/WRENCHBOARD_ACCOUNT_COMPLETE_TOPUP()");
                  return WrenchBoardCompleteBalanceTopup(in, out);
               break;
        case WRENCHBOARD_USER_DELETEACC:
                    return  WrenchBoardDeleteAccount(in, out);
               break;

       case  WRENCHBOARD_ACCOUNT_PRICE_COMBO:
             return getJobPriceCombo(in, out);
       break;

       case  WRENCHBOARD_ACCOUNT_JOBPOST_DURATION:
             return getJobPostDuration(in, out);
       break;

       case  WRENCHBOARD_ACCOUNT_USER_RECIPEINT:
            return getUserRecipientCombo(in, out);
       break;

       case WRENCHBOARD_ACCOUNT_ADD_RECIPEINT:
            return  member_addrecipient(in, out);
       break;

       case  WRENCHBOARD_ACCOUNT_ACCOUNT_TYPES:
            return getAccountTypeCombo(in, out);
       break;

       case  WRENCHBOARD_ACCOUNT_COUNTRY_COMBO:
            return getCountryCombo(in, out);
       break;

       case  WRENCHBOARD_ACCOUNT_JOB_COUNTRY:
            return getCountryJobCombo(in, out);
       break;

       case WRENCHBOARD_ACCOUNT_COUNTRY_BANKS:
            return getBankCombo(in, out);
       break;

       case WRENCHBOARD_ACCOUNT_REFFERHX:
            return  WrenchRefferHx( in, out);
       break;

       case WRENCHBOARD_VERIFY_PENDING_LINK:
             return  VerifyWrenchAccountLink( in, out);
       break;
       case WRENCHBOARD_ACCOUNT_HOMEBANNERS:
         return  WrenchHomeBanners(in, out);
       break;

       case WRENCHBOARD_FAMILY_HOMEBANNERS:
         return WrenchFamilyHomeBanners(in, out);
       break;

       case WRENCHBOARD_ACCOUNT_RECENTS:
         return  WrenchGetRecentDash(in, out);
       break;

       case WRENCHBOARD_ACCOUNT_DASHRECENT:
          return  WrenchRecentDash(in, out);
       break;

       case WRENCHBOARD_ACCOUNT_CONTACTIMPORT:
       // Contact imports
          return  WrenchImportContacts(in, out);
       break;

       case WRENCHBOARD_RESOURCE_MYFILES:
          return  WrenchRegisterMyFileUpload(in, out);
       break;

       case WRENCHBOARD_MYFILES_LIST:
          return  WrenchMyFilesList(in, out);
       break;

       case WRENCHBOARD_ACCOUNT_PREFERENCES:
          return  WrenchAccountUsePrefrence(in, out);
       break;

       case WRENCHBOARD_ACCOUNT_UPDATE_PREFS:
          logfmt(logINFO, "/account_calls() => WRENCHBOARD_ACCOUNT_UPDATE_PREFS");
          return WrenchAccountSetPrefrence(in, out);
       break;

       case  WRENCHBOARD_ACCOUNT_MYPAGE:
          return WrenchMyPage(in, out);
       break;

       case  WRENCHBOARD_ACCOUNT_PAGEINTRO:
          return WrenchMyPageIntro(in, out);
       break;

       case WRENCHBOARD_LOAD_REFERLINK:
          return WrenchLoadReferLink(in, out);
       break;

       case WRENCHBOARD_VIRTUAL_CARDADD:
          return  WrenchRequestVirtualCard(in, out);
       break;

       case WRENCHBOARD_VIRTUAL_FAMILY_CARD:
          return  WrenchRequestFamilyVirtualCard(in, out);
       break;
    }
    logfmt(logINFO, "/account_calls()");
    return ret;
}

#define PHP_API_TRANSFER_COMPLETE  200

long WrenchLoadReferLink(CVars in, CVars &out) {
    logfmt(logINFO, "WrenchMyPageIntro()");
    long ret = PHP_API_BAD_PARAM;
    const PGresult *res;
    char buf[1500];
    CVars x;

		try {
			REQ_STRING(in, "refer_link", 20, 100, "(.*)");
			long action_path    = REQ_LONG(in, "action_path", 1, -1);

			if (action_path ==  200){
               sprintf(buf, "SELECT firstname, lastname, email  FROM promo_member WHERE uid::text='%s' AND status = 1", in["refer_link"].c_str());
			}
			else{
               sprintf(buf, "SELECT firstname, lastname, email  FROM members_refer_friend WHERE refer_link='%s' AND status = 1", in["refer_link"].c_str());
			}

			if ( load_db_record(out, "%s ",  buf) > 0){
	            ret = PHP_API_OK;
			}
			else{
                out["status"] = "Invalid link";
			}

		} catch (bad_parameter) {
		out["status"] = "ERROR";
		}
 return ret;
}

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

    try{
        long member_id    = REQ_LONG(in, "member_id", 1, -1);
        long request_type = REQ_LONG(in, "request_type", 1, -1);

        REQ_STRING(in, "uid", 20, 100, "(.*)");
        REQ_STRING(in, "family_uid", 20, 100, "(.*)");
        REQ_STRING(in, "address", 5, 150, "(.*)");
        REQ_STRING(in, "city", 2, 50, "(.*)");
        REQ_STRING(in, "state", 1, 15, "(.*)");
        REQ_STRING(in, "country", 1, 3, "(.*)");
        REQ_STRING(in, "postal_code", 1, 10, "(.*)");
        REQ_STRING(in, "phone_number", 5, 15, "(.*)");

        long dob_day = REQ_LONG(in, "dob_day", 1, -1);
        long dob_month = REQ_LONG(in, "dob_month", 1, -1);
        long dob_year = REQ_LONG(in, "dob_year", 1, -1);

        const PGresult *res = pgsql_query("SELECT m.uid::text AS target_uid FROM members_family f LEFT JOIN members m ON m.id = f.family_member_id  WHERE f.uid::text='%s'", in["family_uid"].c_str());
        if (res != NULL && pgsql_num_rows(res) > 0) {
            map<const char*, const char*>f = pgsql_fetch_assoc(res, 0);
            CVars rec;
            map_to_cvars(f, rec);
            x["uid"] = in["uid"];  x["uid"].set_valid(true);
            x["member_id"] = member_id;  x["member_id"].set_valid(true);
    		x["member_uid"] =  in["uid"];  x["member_uid"].set_valid(true);
            x["target_uid"] = rec["target_uid"];  x["target_uid"].set_valid(true);  //
            x["address"] = in["address"];  x["address"].set_valid(true);
            x["request_type"] = in["request_type"];  x["request_type"].set_valid(true);
            x["city"] = in["city"];  x["city"].set_valid(true);
            x["state"] = in["state"];  x["state"].set_valid(true);
            x["country"] = in["country"];  x["country"].set_valid(true);
            x["postal_code"] = in["postal_code"];  x["postal_code"].set_valid(true);
            x["phone_number"] = in["phone_number"];  x["phone_number"].set_valid(true);
            x["dob_day"] = in["dob_day"];  x["dob_day"].set_valid(true);
            x["dob_month"] = in["dob_month"];  x["dob_month"].set_valid(true);
            x["dob_year"] = in["dob_year"];  x["dob_year"].set_valid(true);
            return WrenchRequestVirtualCard( x, out );
        } else {



        }
    } catch (bad_parameter) {
       out["status"] = "ERROR";
    }
    return ret;
}

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

    try{
        long member_id    = REQ_LONG(in, "member_id", 1, -1);
        long request_type = REQ_LONG(in, "request_type", 1, -1);

        REQ_STRING(in, "uid", 20, 100, "(.*)");
        REQ_STRING(in, "target_uid", 20, 100, "(.*)");
        REQ_STRING(in, "address", 5, 150, "(.*)");
        REQ_STRING(in, "city", 2, 50, "(.*)");
        REQ_STRING(in, "state", 1, 15, "(.*)");
        REQ_STRING(in, "country", 1, 3, "(.*)");
        REQ_STRING(in, "postal_code", 1, 10, "(.*)");
        REQ_STRING(in, "phone_number", 5, 15, "(.*)");

        long dob_day = REQ_LONG(in, "dob_day", 1, -1);
        long dob_month = REQ_LONG(in, "dob_month", 1, -1);
        long dob_year = REQ_LONG(in, "dob_year", 1, -1);

        const PGresult *res = pgsql_query("SELECT id AS request_id FROM members_card_request WHERE member_id=%lu AND status=1000", member_id);
        if (res != NULL && pgsql_num_rows(res) > 0) {

        } else {
            x["member_id"] = member_id;  x["member_id"].set_valid(true);
    		x["member_uid"] =  in["uid"];  x["member_uid"].set_valid(true);
            x["target_uid"] = in["target_uid"];  x["target_uid"].set_valid(true);
            x["address"] = in["address"];  x["address"].set_valid(true);
            x["request_type"] = in["request_type"];  x["request_type"].set_valid(true);
            x["city"] = in["city"];  x["city"].set_valid(true);
            x["state"] = in["state"];  x["state"].set_valid(true);
            x["country"] = in["country"];  x["country"].set_valid(true);
            x["postal_code"] = in["postal_code"];  x["postal_code"].set_valid(true);
            x["phone_number"] = in["phone_number"];  x["phone_number"].set_valid(true);
            x["dob_day"] = in["dob_day"];  x["dob_day"].set_valid(true);
            x["dob_month"] = in["dob_month"];  x["dob_month"].set_valid(true);
            x["dob_year"] = in["dob_year"];  x["dob_year"].set_valid(true);
            long sid = insert_db_record(DBS_VALID, "members_card_request", "members_card_request_id_seq", x);
            if ( sid  > 0 ){
                 load_db_record(out, "SELECT id AS request_id, uid AS request_uid FROM members_card_request WHERE id = %lu ", sid);
                 account_email(WRENCHBOARD_VIRTUAL_CARDADD, out, out);
                 ret = PHP_API_OK;
            }

        }
    } catch (bad_parameter) {
       out["status"] = "ERROR";
    }
    return ret;
}

long WrenchImportContacts(CVars in, CVars &out) {
    long ret = PHP_API_BAD_PARAM;
    logfmt(logINFO, "long WrenchImportContacts(CVars in, CVars out)");
    //REQ_STRING(in, "raw_contacts", 0, 5500, "(.*)");
    long member_id = REQ_LONG(in, "member_id", 1, -1);
	REQ_STRING(in, "member_uid", 20, 100, "(.*)");
    CVars x;
    const PGresult *res = pgsql_query("SELECT id AS import_id FROM members_contacts_import WHERE member_id=%lu", member_id);
    if (res != NULL && pgsql_num_rows(res) > 0) {
        map<const char*, const char*>f = pgsql_fetch_assoc(res, 0);
        CVars rec;
        map_to_cvars(f, rec);

        x["raw_contacts"] = in["raw_contacts"];
        x["raw_contacts"].set_valid(true);
        update_db_record(DBS_VALID, "members_contacts_import", x, rec["import_id"].Long());
        ret = PHP_API_OK;
    } else {
        x["member_id"] = member_id;
        x["member_id"].set_valid(true);
		x["member_uid"] =  in["member_uid"];
		x["member_uid"].set_valid(true);
        x["raw_contacts"] = in["description"];
        x["raw_contacts"].set_valid(true);
        long sid = insert_db_record(DBS_VALID, "members_contacts_import", "members_contacts_import_id_seq", x);
        ret = PHP_API_OK;
    }
    return ret;
}

long WrenchMyPage(CVars in, CVars &out) {
    logfmt(logINFO, "WrenchMyPageIntro()");
    long ret = PHP_API_BAD_PARAM;
    const PGresult *res;
    CVars x;

		try {
			REQ_LONG(in, "member_id", 1, -1);
			REQ_STRING(in, "uid", 3, 150, "(.*)");

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

			if ( load_db_record(out, "SELECT d.id AS detail_id,d.* FROM members_detail d "
			                        "LEFT JOIN members m ON m.id =d.member_id "
									"WHERE d.member_id=%lu  AND  m.uid='%s' AND m.status = 1 ", in["member_id"].Long(), in["uid"].c_str()) > 0){
	            ret = PHP_API_OK;
			}
			else{
                out["intro"] = "";
                out["description"] = "";
			}

		} catch (bad_parameter) {
		out["status"] = "ERROR";
		}
 return ret;
}

long WrenchMyPageIntro(CVars in, CVars &out) {
    logfmt(logINFO, "WrenchMyPageIntro()");
    long ret = PHP_API_BAD_PARAM;
    const PGresult *res;
	CVars cc;
    CVars x;

		try {
			REQ_LONG(in, "member_id", 1, -1);
			REQ_STRING(in, "uid", 3, 150, "(.*)");
			REQ_STRING(in, "intro", 3, 150, "(.*)");
			REQ_STRING(in, "description", 3, 450, "(.*)");

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

			if ( load_db_record(cc, "SELECT d.id AS detail_id FROM members_detail d "
			                        "LEFT JOIN members m ON m.id =d.member_id "
									"WHERE d.member_id=%lu  AND  m.uid='%s' AND m.status = 1 ", in["member_id"].Long(), in["uid"].c_str()) > 0){
				update_db_record(DBS_VALID, "members_detail", x, cc["detail_id"].Long());
			}
			else{
				x["member_id"] = in["member_id"];
				x["member_id"].set_valid(true);
                out["detail_id"] = insert_db_record(DBS_VALID, "members_detail", "members_detail_id_seq", x);
			}
			ret = PHP_API_OK;
		} catch (bad_parameter) {
		out["status"] = "ERROR";
		}

 return ret;
}
/* THIS IS TO BE RETIRED */
long WrenchUpdateAccountDescription(CVars in, CVars &out) {
    long ret = PHP_API_BAD_PARAM;
    logfmt(logINFO, "long WrenchUpdateAccountDescription(CVars in, CVars out)");
    REQ_STRING(in, "description", 0, 500, "(.*)");
    long member_id = REQ_LONG(in, "member_id", 1, -1);
    CVars x;
    const PGresult *res = pgsql_query("SELECT id AS detail_id FROM members_detail WHERE member_id=%lu", member_id);
    if (res != NULL && pgsql_num_rows(res) > 0) {
        map<const char*, const char*>f = pgsql_fetch_assoc(res, 0);
        CVars rec;
        map_to_cvars(f, rec);

        x["description"] = in["description"];
        x["description"].set_valid(true);
        update_db_record(DBS_VALID, "members_detail", x, rec["detail_id"].Long());
        ret = PHP_API_OK;
    } else {
        x["member_id"] = member_id;
        x["member_id"].set_valid(true);
        x["description"] = in["description"];
        x["description"].set_valid(true);
        long sid = insert_db_record(DBS_VALID, "members_detail", "members_detail_id_seq", x); //members_session_id_seq
        ret = PHP_API_OK;
    }
    return ret;
}
/*

CREATE TABLE members_recentactivities (
		id SERIAL,
		member_id INT REFERENCES members(id) NOT NULL,
		uid  uuid  DEFAULT uuid_generate_v4(),
		title VARCHAR(35) NOT NULL,
		description VARCHAR(100),
		status INT DEFAULT 1,
		added timestamp without time zone DEFAULT now()
	);
 ALTER TABLE ONLY members_recentactivities
    ADD CONSTRAINT members_recentactivities_id_key UNIQUE (id);

CREATE TABLE members_myfiles (
	id SERIAL,
	member_id INT REFERENCES members(id) NOT NULL,
	uid  uuid  DEFAULT uuid_generate_v4(),
	file_name VARCHAR(35),
	saved_file_name VARCHAR(35) UNIQUE NOT NULL,
	file_size INT DEFAULT 0,
	file_type VARCHAR(15),
	title VARCHAR(35),
	description VARCHAR(100),
	status INT DEFAULT 1,
    added timestamp without time zone DEFAULT now(),
    updated timestamp without time zone DEFAULT now()
	);
 ALTER TABLE ONLY members_myfiles
    ADD CONSTRAINT members_myfiles_id_key UNIQUE (id);

*/
long WrenchJobCount(long member_id);
long WrenchFamilyCount(long member_id);

long WrenchGetRecentDash(CVars in, CVars &out) {

logfmt(logINFO, "WrenchGetRecentDash()");
    char vname[30];
    long ret = PHP_API_BAD_PARAM;

	REQ_LONG(in, "member_id", 1, -1);
	REQ_STRING(in, "sessionid", 2, 149, "(.*)");

    try {
         REQ_LONG(in, "member_id", 1, -1);
         out["total_record"] = "0";
        const PGresult *res;
        res = pgsql_query("SELECT * FROM members_recentactivities WHERE member_id = %lu ORDER BY added DESC LIMIT 6", 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), "title_%05d", i);
                out[vname] = rec["title"];

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

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

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

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

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

    return ret;
}

/*
Called directly for country list at signup

wrenchboard=> SELECT code,country,phone_code,jobs FROM country
              WHERE allow is not null AND status  = 1 ORDER BY country ASC;
 code |    country    | phone_code |            jobs
------+---------------+------------+----------------------------
 GH   | Ghana         | 233        |
 NG   | Nigeria       | 234        | 2022-04-09 20:43:48.007359
 US   | United States | 1          |
(3 rows)

*/
long WrenchSignUpCountry(CVars in, CVars &out) {
    char vname[30];
    long ret = PHP_API_BAD_PARAM;
    logfmt(logINFO, "WrenchSignUpCountry()");


    try {
        out["total_record"] = "0";
        const PGresult *res;
        res = pgsql_query("SELECT code,country,phone_code,jobs,uid FROM country "
                           " WHERE allow is not null AND status  = 1 ORDER BY country 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), "code_%05d", i);
                out[vname] = rec["code"];

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

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

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

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

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

long WrenchRegisterMyFileUpload(CVars in, CVars &out) {
    long ret = PHP_API_BAD_PARAM;
    logfmt(logINFO, "WrenchRegisterMyFileUpload()");
    try {
        REQ_LONG(in, "member_id", 1, -1);
        REQ_STRING(in, "uid", 3, 150, "(.*)");
        REQ_STRING(in, "file_name", 5, 35, "(.*)");
        REQ_STRING(in, "message", 5, 35, "(.*)");  //message

        REQ_STRING(in, "title", 5, 35, "(.*)");
        REQ_STRING(in, "description", 5, 100, "(.*)");

        CVars xx;
		xx["member_id"] = in["member_id"]; xx["member_id"].set_valid(true);
		xx["file_name"]    = in["file_name"];    xx["file_name"].set_valid(true);
		xx["saved_file_name"] = in["message"]; xx["saved_file_name"].set_valid(true);

		xx["file_size"]    = in["file_size"];    xx["file_size"].set_valid(true);
		xx["file_type"] = in["file_type"]; xx["file_type"].set_valid(true);

		xx["title"]    = in["title"];    xx["title"].set_valid(true);
		xx["description"] = in["description"]; xx["description"].set_valid(true);

		out["saved_id"] = insert_db_record(DBS_VALID, "members_myfiles", "members_myfiles_id_seq", xx);

		if ( out["saved_id"].Long() > 0){
		       // lets find teh customer now
		        if ( load_db_record(out, "SELECT uid AS myfile_uid, * FROM members_myfiles WHERE id = %lu ", out["saved_id"].Long()) > 0){
                    ret = PHP_API_OK;
		        }
		}

    }    catch (bad_parameter) {
        out["log_status"] = "Something went wrong";
    }
    logfmt(logINFO, "WrenchRegisterMyFileUpload()");
    return ret;
}


long WrenchFlutterCreditHook(CVars in, CVars &out) {
    long ret = PHP_API_BAD_PARAM;
    logfmt(logINFO, "WrenchFlutterCreditHook()");
    try {
        REQ_STRING(in, "txRef", 2, 50, "(.*)");
        REQ_STRING(in, "flwRef", 2, 50, "(.*)");

        CVars xx;
		xx["event_type"] = in["event_type"]; xx["event_type"].set_valid(true);
		xx["status"]    = in["status"];    xx["status"].set_valid(true);
		xx["txRef"] = in["txRef"]; xx["txRef"].set_valid(true);
		xx["flwRef"]    = in["flwRef"];    xx["flwRef"].set_valid(true);
		xx["orderRef"] = in["orderRef"]; xx["orderRef"].set_valid(true);
		xx["amount"]    = in["amount"];    xx["amount"].set_valid(true);
		xx["appfee"] = in["appfee"]; xx["appfee"].set_valid(true);
		xx["AccountId"]    = in["AccountId"];    xx["AccountId"].set_valid(true);
		xx["customer_id"] = in["customer_id"]; xx["customer_id"].set_valid(true);
		xx["fullName"]    = in["fullName"];    xx["fullName"].set_valid(true);
		xx["raw_result"] = in["raw_result"]; xx["raw_result"].set_valid(true);
		out["hook_id"] = insert_db_record(DBS_VALID, "flutterwave_hooks", "flutterwave_hooks_id_seq", xx);

		if ( out["hook_id"].Long() >  0 && in["status"] == "successful"){
		       // lets find teh customer now
		       CVars cc;
		        if ( load_db_record(cc, "SELECT member_id, uid,amount,currency FROM members_credit WHERE uid = '%s'", xx["txRef"].c_str()) > 0){
                    CVars xn;
                    xn["member_id"] = cc["member_id"]; xn["member_id"].set_valid(true);
                    xn["amount"] = cc["amount"]; xn["amount"].set_valid(true);
                    xn["currency"] = cc["currency"]; xn["currency"].set_valid(true);
                    xn["transaction_id"] = xx["txRef"]; xn["transaction_id"].set_valid(true);
                    logfmt(logINFO, "WrenchBoardStartBalanceTopup() start ***** ");
                    long trx_id =  WrenchBoardStartBalanceTopup(xn, out);
                        if ( trx_id >  0 ){
                            CVars tx;
                            tx["return_status"] = in["status"]; tx["return_status"].set_valid(true);
                            tx["status"] = "5";  tx["status"].set_valid(true);
                            tx["tx_ref"] = xx["txRef"];  tx["tx_ref"].set_valid(true);
                            tx["transaction_id"] = xx["txRef"];  tx["transaction_id"].set_valid(true);
                            tx["flutterwave_payments_id"] = trx_id;  tx["flutterwave_payments_id"].set_valid(true);
                            logfmt(logINFO, "WrenchBoardCompleteBalanceTopup() call ***** ");
                            long credit_id =   WrenchBoardCompleteBalanceTopup(tx, out);
                            if (credit_id > 0 ){
                              ret = PHP_API_OK;
                              out["log_status"] = "completed";
                            }

                        }
		        }
		}




    }    catch (bad_parameter) {
        out["log_status"] = "Something went wrong";
    }
    logfmt(logINFO, "/out WrenchFlutterCreditHook()");
    return ret;
}

long  WrenchBoardStartBalanceTopup(CVars in, CVars &out){
 logfmt(logINFO, "WrenchBoardStartBalanceTopup()");
 long trx_id = 0;
/*
$data['tx_ref'] = 'wrench-'.rand(1000000000,9999999999);
        $data['currency'] = "NGN";
        $data['customer_email'] = $_SESSION['username'];
        $data['customer_phone_number'] = '';
        $data['customer_name'] = $_SESSION['firstname'].' '.$_SESSION['lastname'];
        $data['consumer_id']  = $_SESSION['member_id'];
        $data['consumer_mac'] = $_SESSION['member_id']."-912ba-1192a";
        $data['redirect_url'] = base_url() . "dash"; //"https://oameye.work.wrenchboard.com/dash";
        $data['public_key'] = "FLWPUBK_TEST-54c90141b028789d671067bd72f781a9-X";
*/
  out["public_key"] = CfgReadChar("flutterwave.public_key");

  try {
		REQ_LONG(in, "member_id", 1, -1);
		REQ_LONG(in, "amount", 1, -1);
		REQ_STRING(in, "currency", 2, 10, "(.*)");
		REQ_STRING(in, "transaction_id", 2, 50, "(.*)");

        CVars x;
            x["member_id"] = in["member_id"];
            x["member_id"].set_valid(true);
            x["amount"] = in["amount"];
            x["amount"].set_valid(true);
            x["currency"] = in["currency"];
            x["currency"].set_valid(true);
            x["transaction_id"] = in["transaction_id"];
            x["transaction_id"].set_valid(true);

        trx_id = insert_db_record(DBS_VALID, "flutterwave_payments", "flutterwave_payments_id_seq", x);

        if (trx_id > 0) {
           load_db_record(out, "SELECT fp.member_id AS consumer_id,fp.tx_ref,fp.tx_ref,fp.currency,m.phone,m.uid AS consumer_mac " \
		   "FROM flutterwave_payments fp LEFT JOIN members m ON m.id=fp.member_id WHERE fp.id =%lu",trx_id);
		}
		out["status"] = "OK";
    } catch (bad_parameter) {
        logfmt(logINFO, "ERROR CALL long WrenchBoardStartBalanceTopup(CVars in, CVars &out)");
    }
    return trx_id;
}

long WrenchDeleteUsersCCard(CVars in, CVars &out) {
    logfmt(logINFO, "VerifyWrenchAccountLink()");
    long ret = PHP_API_BAD_PARAM;
    const PGresult *res;



            try {
                REQ_LONG(in, "member_id", 1, -1);
                REQ_STRING(in, "uid", 3, 150, "(.*)");
                REQ_STRING(in, "card_uid", 3, 150, "(.*)");
                long delete_status = 0;

                res = pgsql_query("SELECT id FROM creditcard WHERE member_id=%lu  AND  uid='%s' AND active = 1 ", in["member_id"].Long(), in["card_uid"].c_str());
                if (res != NULL && pgsql_num_rows(res) > 0) {
                pgsql_exec("UPDATE creditcard SET active=%lu WHERE member_id=%lu  AND  uid='%s' AND active = 1 ",delete_status, in["member_id"].Long(), in["card_uid"].c_str());
                out["status"] = "completed";
            }
            ret = PHP_API_OK;


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

return ret;
}


long VerifyWrenchAccountLink(CVars in, CVars &out) {
    logfmt(logINFO, "VerifyWrenchAccountLink()");
    long ret = PHP_API_BAD_PARAM;
    const PGresult *res;
    REQ_STRING(in, "verify_link", 2, 120, "(.*)");
    OPTIONAL(in, "loc") REQ_STRING(in, "loc", 3, 15, "(.*)");
     out["status_text"] = "Start";
     out["status"] = "-1";
    try {
    		res = pgsql_query("SELECT uid AS pending_uid,id AS pending_id,username "
    		                  " FROM members_pending WHERE verify_link ='%s' AND expire > now() "
    		                  " AND status = 1 LIMIT 1",in["verify_link"].c_str());
    		if (res != NULL && pgsql_num_rows(res) > 0) {
                map<const char*, const char*>f = pgsql_fetch_assoc(res, 0);
                CVars rec;
                map_to_cvars(f, rec);
                out["pending_uid"] = rec["pending_uid"]; out["pending_uid"].set_valid( true );
                out["pending_id"]  = rec["pending_id"];  out["pending_id"].set_valid( true );
                out["username"]  =  rec["username"];
                out["status_text"] = "Link Verified";
                out["status"] = "0";
                ret = PHP_API_OK;
    		}

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

    logfmt(logINFO, "/VerifyWrenchAccountLink()");
    return ret;
}

long  WrenchBoardDeleteAccount(CVars in, CVars &out)
{
    long ret = 0;
    REQ_LONG(in, "member_id", 1, -1);
    REQ_STRING(in, "reason", 2, 149, "(.*)");
    CVars xx;
        xx["member_id"] = in["member_id"]; xx["member_id"].set_valid(true);
        xx["reason"]    = in["reason"];    xx["reason"].set_valid(true);
        out["delete_id"] = insert_db_record(DBS_VALID, "members_delete", "members_delete_id_seq", xx);
    ret = PHP_API_OK;
    /*
    DO THE DELETE HERE NOW
    */
return ret;
}

long  WrenchBoardTopupResult(CVars in, CVars &out){
    logfmt(logINFO, "WrenchBoardTopupResult()");
    const PGresult *res;
    const PGresult *res0;
    long ret = PHP_API_BAD_PARAM;

      try {
            REQ_STRING(in, "tx_ref", 2, 50, "(.*)");
            REQ_STRING(in, "uid", 3, 50, "(.*)");
            REQ_LONG(in, "member_id", 1, -1);

            res0 = pgsql_query("SELECT * FROM members_credit WHERE uid ='%s' AND member_id=%lu",in["tx_ref"].c_str(),in["member_id"].Long());
            if (res0 != NULL && pgsql_num_rows(res0) > 0) {

            }
            else{
                 out["status_message"] = "invalid_reference_for_member";
                 return PHP_API_BAD_PARAM;
            }

            res = pgsql_query("SELECT return_status,payment_id from flutterwave_payments where transaction_id='%s'",in["tx_ref"].c_str());
            if (res != NULL && pgsql_num_rows(res) > 0) {
                    map<const char*, const char*>f = pgsql_fetch_assoc(res, 0);
                    CVars rec;
                    map_to_cvars(f, rec);

                    out["return_status"] = rec["return_status"]; out["return_status"].set_valid( true );
                    in["payment_id"]     = rec["payment_id"];    in["payment_id"].set_valid( true );
                    if ( in["payment_id"] !=""  && in["payment_id"].Long() >  0 ){
                        load_db_record( out, "SELECT confirmation FROM members_payments WHERE id  = %lu",  in["payment_id"].Long());
                    }
                     ret = PHP_API_OK;
            }
            out["status"] = "OK";
        } catch (bad_parameter) {
            logfmt(logINFO, "ERROR CALL long WrenchBoardTopupResult(CVars in, CVars &out)");
        }
         logfmt(logINFO, "/out ****************    WrenchBoardTopupResult()");
    return ret;
}

long  WrenchBoardCompleteBalanceTopup(CVars in, CVars &out){
 logfmt(logINFO, "WrenchBoardCompleteBalanceTopup()");
 long trx_id = 0;
 const PGresult *res;

  try {
        REQ_STRING(in, "tx_ref", 2, 50, "(.*)");
       // REQ_STRING(in, "transaction_id", 2, 50, "(.*)"); Handled else where
        REQ_LONG(in, "status", 1, -1);
        REQ_LONG(in, "flutterwave_payments_id", 1, -1);

		//res = pgsql_query("SELECT id AS trx_id,member_id FROM flutterwave_payments WHERE tx_ref = '%s' AND status=0",in["tx_ref"].c_str());
		res = pgsql_query("SELECT id AS trx_id,member_id,tx_ref FROM flutterwave_payments WHERE id = %lu AND status=0",in["flutterwave_payments_id"].Long());
		if (res != NULL && pgsql_num_rows(res) > 0) {
				map<const char*, const char*>f = pgsql_fetch_assoc(res, 0);
				CVars rec;
			    map_to_cvars(f, rec);
				
				in["member_id"] = rec["member_id"]; in["member_id"].set_valid( true );
				in["trx_id"] = rec["trx_id"]; in["trx_id"].set_valid( true );
				
              /*  pgsql_exec("UPDATE flutterwave_payments SET transaction_id = '%s', " \
				"status=%lu,updated=now(),return_status='%s' WHERE id = %lu AND status=0 AND " \
				"tx_ref='%s' ", in["transaction_id"].c_str(),in["status"].Long(),in["return_status"].c_str(),rec["trx_id"].Long(), in["tx_ref"].c_str());
				*/
                pgsql_exec("UPDATE flutterwave_payments SET  " \
                "status=%lu,updated=now(),return_status='%s' WHERE  status=0 AND " \
                " id= %lu ",in["status"].Long(),in["return_status"].c_str(), in["flutterwave_payments_id"].Long());

					if ( in["status"].Long() ==  5){

					 in["tx_ref"] = rec["tx_ref"];  in["tx_ref"].set_valid( true );  // note we change tx_ref here
					 return  WrenchMemberTopupPayment( in, out ); // This start the actual crediting
					}
		}
		out["status"] = "OK";
    } catch (bad_parameter) {
        logfmt(logINFO, "ERROR CALL long WrenchBoardCompleteBalanceTopup(CVars in, CVars &out)");
    }
    return trx_id;
}



long WrenchBoardMobileSendUserWallet(CVars in, CVars &out) {
  logfmt(logINFO, "WrenchBoardMobileSendUserWallet()");
    char vname[30];
    long ret = PHP_API_BAD_PARAM;

	REQ_LONG(in, "member_id", 1, -1);
	REQ_STRING(in, "sessionid", 2, 149, "(.*)");
	logfmt(logINFO, "WrenchBoardMobileSendUserWallet() Verify Session ");	
	if ( VerifySession(in, out) != PHP_API_OK ){
	   return 0;
	}
		/*
		    public function getUserEscrowWallet($member_id) {
                $mysql = "SELECT sum(amount),currency FROM members_payments WHERE code ='OFDPS' AND member_id = $member_id  AND confirmation IS NOT NULL  AND flags =  4 GROUP BY currency";
                $query = $this->db->query($mysql);
                return $query->result_array();
            }
		*/
    try {
        REQ_LONG(in, "member_id", 1, -1);
        out["total_record"] = "0";
        const PGresult *res;
        res = pgsql_query("SELECT w.amount,c.*,w.amount AS current_balance,c.country,w.transfer_limit,w.uid AS wallet_uid "
                           "FROM members_wallet w LEFT JOIN currency c ON c.code=w.currency "
                            "WHERE w.member_id = %lu AND w.status = 1 ORDER BY c.lorder DESC", 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), "amount_%05d", i);
                out[vname] = rec["amount"];
                snprintf(vname, sizeof (vname), "currency_%05d", i);
                out[vname] = rec["currency"];

                // amount  | id | code  | description | symbol |  action_type  | lorder | current_balance
                snprintf(vname, sizeof (vname), "description_%05d", i);
                out[vname] = rec["description"];

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

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

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

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

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

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

                snprintf(vname, sizeof (vname), "processor_%05d", i);
                out[vname] = rec["processor"];
            }

                 const PGresult *res2;
//                 res2 = pgsql_query("SELECT sum(amount) AS escrow,currency FROM members_payments WHERE code ='OFDPS' AND member_id = %lu  "
//                                     "AND confirmation IS NOT NULL  AND flags =  4 GROUP BY currency", in["member_id"].Long());

                res2 = pgsql_query("SELECT sum(p.amount) AS escrow,p.currency "
                                    " FROM members_payments p  "
                                    " LEFT JOIN members_jobs_offer o ON o.payment_id = p.id "
                                    " WHERE p.code ='OFDPS' AND p.member_id = %lu "
                                    " AND p.confirmation IS NOT NULL "
                                    " AND p.flags = 4 AND o.status=1 "
                                    " GROUP BY p.currency", in["member_id"].Long());


                if (res2 != NULL && pgsql_num_rows(res2) > 0) {
                 for (int i = 0, n = pgsql_num_rows(res); i < n; i++) {
                        map<const char*, const char*>f = pgsql_fetch_assoc(res2, i);
                        if (f.empty()) continue;
                        CVars rec2;
                        map_to_cvars(f, rec2);
                            snprintf(vname, sizeof (vname), "escrow_%s", rec2["currency"].c_str());
                            out[vname] = rec2["escrow"];
                        }
                }

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

}

long WrenchBoardMobileSendJobInterest(CVars in, CVars &out) {
    long ret = PHP_API_BAD_PARAM;
    try {
        REQ_LONG(in, "job_id", 1, -1);
        REQ_LONG(in, "member_id", 1, -1);
        REQ_STRING(in, "sessionid", 2, 149, "(.*)");

        
         if ( load_db_record(out, "SELECT offer_code FROM members_jobs_offer WHERE id ='%lu' AND expire>= now() AND status = 1 AND public_view > 0", in["job_id"].Long())> 0){
             in["offer_code"] = out["offer_code"];
             in["offer_code"].set_valid( true );
             
              ret =  WrenchJobsOfferInterest(in, out);
              if ( ret == PHP_CREATED_OK ){
                  ret = 200;
              }
              else{
                  ret = 100; //  message will be in the status string to display 
              }
         }
         
         
        /*
         
         $data = $this->getSessionArray();
        $data['offer_code'] = $this->input->get('job_contract');
        $data['member_id'] = $_SESSION['member_id']; // just maing sure

        $data['action'] = WRENCHBOARD_JOB_SEND_INTEREST;
        $this->load->model('backend_model');
        $out = array();
        $res = $this->backend_model->wrenchboard_api($data, $out);
        if ($res == PHP_CREATED_OK) {
            echo 'Success - ' . $out['status'];
        } else {
            echo 'Error - ' . $out['status'];
        }
         
         */
        
        


    }    catch (bad_parameter) {
        out["log_status"] = "Invalid Log Action";
    }
    return ret;
}
long  WrenchBoardMobileSendMoney(CVars in, CVars &out){
    logfmt(logINFO, "long ***************  WrenchBoardMobileSendMoney(CVars in, CVars out)");
	long ret = PHP_API_BAD_PARAM;

	try{
	REQ_LONG(in, "member_id", 1, -1);
	REQ_STRING(in, "uid", 3, 150, "(.*)");
	REQ_STRING(in, "wallet_uid", 3, 150, "(.*)");
	long mode = REQ_LONG(in, "mode", 1, -1);
	REQ_STRING(in, "TerminatingCountryCode", 2, 5, "(.*)");
	REQ_LONG(in, "amount", 1, -1);


    in["senderid"] = in["member_id"]; // some parts uses senderid
    in["senderid"].set_valid( true );

    // $in["TerminatingCountryCode"] = 'NG'; // NG - Nigeria

    // LET CHECK IF YOU HAVE THE WALLET
    CVars wl;
    if ( load_db_record(wl, "SELECT w.*,c.country from members_wallet w LEFT join currency c ON c.code=w.currency"
    " WHERE c.country='%s' AND w.member_id=%lu AND w.uid='%s' ",in["TerminatingCountryCode"].c_str(), in["member_id"].Long(),in["wallet_uid"].c_str())> 0){
        if (in["amount"].Long() > wl["transfer_limit"].Long() )
        { out["status_message"] = "tranfer_amount_limit_error";
               return ret;
        }
    }
    else
    {
         out["status_message"] = "wallet_not_found_error";
         return ret;
    }



	switch(mode){
        case WRENCH_EXISTING_ACCOUNT:
             REQ_STRING(in, "recipient_uid", 3, 150, "(.*)");
             if ( load_db_record(out, "SELECT id AS recipientid FROM sendmoney_recipient "
                                      " WHERE uid ='%s' AND member_id = %lu AND status = 1 "
                                      " AND country='%s' ",in["recipient_uid"].c_str(), in["member_id"].Long(),in["TerminatingCountryCode"].c_str())> 0){
                    in["recipientid"] = out["recipientid"];  in["recipientid"].set_valid( true );
                    in["bankid"] = out["recipientid"];  in["bankid"].set_valid( true );
             }
             else
             {
                 out["status_message"] = "invalid_recipient_error";
                 return ret;
             }
        break;
        case WRENCH_NEWBANK_ACCOUNT:
            CVars rp;
             REQ_STRING(in, "bank_uid", 3, 150, "(.*)");
             REQ_STRING(in, "account_no", 5, 15, "(.*)");

             REQ_STRING(in, "country", 2, 3, "(.*)");
             REQ_STRING(in, "state", 2, 49, "(.*)");
             REQ_STRING(in, "city", 2, 49, "(.*)");

             long account_type = REQ_LONG(in, "account_type", 1, -1);
            if ( load_db_record(wl, "SELECT firstname,lastname FROM members WHERE uid = '%s' ",in["uid"].c_str())> 0){
               rp["firstname"] = wl["firstname"]; rp["firstname"].set_valid( true );
               rp["lastname"]  = wl["lastname"];  rp["lastname"].set_valid( true );
                /*
                wrenchboard=>  SELECT * FROM bank_entity_codes WHERE uid = 'a2c6c1a2-5cf2-4396-8630-50c47da15316';
                 country | channel |    name     | code | gid | status | bank_codes |                 uid
                ---------+---------+-------------+------+-----+--------+------------+--------------------------------------
                 NG      | INTERSW | Access Bank | 044  |   1 |      1 | ACC044     | a2c6c1a2-5cf2-4396-8630-50c47da15316
                (1 row)

                /var/www/html/public/wrenchboard/wrenchboard_class.php:208:
                array (size=12)
                  'member_id' => int 1
                  'sessionid' => string 'F9A1FB1098B7542EA6AFB627DBD5263638171883CA0CC951DC6C4FB184280EB3' (length=64)
                  'uid' => string '3119b744-42ad-4834-bb83-b737588754ca' (length=36)
                  'firstname' => string 'Firstn' (length=6)
                  'lastname' => string 'Lastn' (length=5)
                  'bank_code' => string '033' (length=3)
                  'account_no' => string '1234567890' (length=10)
                  'account_type' => int 1
                  'country' => string 'NG' (length=2)
                  'state' => string 'Lagos' (length=5)
                  'city' => string 'Lagos' (length=5)
                  'accitytion' => int 11176
                */
                // Lets find the bank now
                 if ( load_db_record(wl, "SELECT * FROM bank_entity_codes WHERE uid = '%s' AND country ='%s' ",in["bank_uid"].c_str(),in["TerminatingCountryCode"].c_str())> 0){
                        rp["account_no"] = in["account_no"]; rp["account_no"].set_valid( true );
                        rp["account_type"]  = in["lastname"];  rp["account_type"].set_valid( true );
                        rp["bank_code"] = wl["code"]; rp["bank_code"].set_valid( true );
                        rp["country"]  = in["TerminatingCountryCode"];  rp["country"].set_valid( true );
                        rp["state"] = in["state"]; rp["state"].set_valid( true );
                        rp["city"]  = in["city"];  rp["city"].set_valid( true );

                        rp["member_id"]    = in["member_id"]; rp["member_id"].set_valid( true );
                        rp["uid"]          = in["uid"];       rp["uid"].set_valid( true );
                        rp["account_type"] = in["account_type"];  rp["account_type"].set_valid( true );

                        long recipientid  =  member_addrecipient(rp, out);
                        if (recipientid > 0 ){
                            in["recipientid"] =recipientid;  in["recipientid"].set_valid( true );
                            in["bankid"]      =recipientid;  in["bankid"].set_valid( true );
                        }
                        else{
                            out["status_message"] = "recipient_add_error";
                            return ret;
                        }
                 }

            }
        break;
	}

		int r1, r2, r3;
        char send_trxid[25];
        srand(time(NULL));
        r1 = abs(rand()*1000);
        srand(time(NULL));
        r2 = abs(rand() * r1);
        srand(time(NULL));
        r3 = abs(rand() * r2);
        sprintf(send_trxid, "T%04lu", r1);
		
		logfmt(logINFO, "Recipient ID =====() %lu",in["bankid"].Long() );
                out["sendmoney_message"] ="Processing...";

		
		REQ_LONG(in, "bankid", 1, -1);
        REQ_LONG(in, "recipientid", 1, -1);
		REQ_STRING(in, "sessionid", 2, 149, "(.*)");
		OPTIONAL(in, "comment") REQ_STRING(in, "comment", 2, 149, "(.*)");
		OPTIONAL(in, "loc") REQ_STRING(in, "loc", 3, 15, "(.*)");

				
				
		in["action"] =  WRENCHBOARD_SMONEY_MEMBER;
		in["InitiatingEntityCode"] = "MBA";
		in["InitiatingAmount"] =  in["amount"];
		
		long fee = member_sendmoney_fee(in, out);
		
		in["Fee"] =  fee;

		in["InitiatingChannel"] = "7";
		in["InitiatingPaymentMethodCode"] = "CA";
		in["InitiatingCurrencyCode"] = "566"; 
		//in["recipientid"] =  in["bankid"]; in["recipientid"].set_valid( true );
		in["transaction_id"] = send_trxid; in["transaction_id"].set_valid( true );
		in["TerminatingPaymentMethodCode"] = "AC";
		in["TerminatingAmount"] = in["amount"];
		in["TerminatingCurrencyCode"] = "566"; 
		in["TerminatingCountryCode"] = "NG"; 
			
			logfmt(logINFO, "Recipient ID Final =====() %lu",in["recipientid"].Long() );
			 ret =  smoney_calls(in, out);
				if ( ret == PHP_API_OK){
				out["sendmoney_message"] ="Completed - Estimated delivery time is 2 to 4 Hours.";
				 out["status_message"] = "complete_standard_processing";
				ret =  PHP_API_TRANSFER_COMPLETE;
				}
				
				
	
		
		    } catch (bad_parameter) {
        out["log_status"] = "Invalid Log Action";
    }
    logfmt(logINFO, "/long WrenchBoardMobileSendMoney(CVars in, CVars out)");
    return ret;
}


long WrenchLoadDashData(CVars in, CVars &out) {
    logfmt(logINFO, "WrenchLoadDashData()");
    char vname[30];
    long ret = PHP_API_BAD_PARAM;

    try {
        long member_id = REQ_LONG(in, "member_id", 1, -1);
        REQ_STRING(in, "uid", 3, 150, "(.*)");
        //  REQ_LONG(in, "page", 1, -1);
        // const PGresult *res;

        const PGresult *res = pgsql_query("SELECT * FROM members WHERE id=%lu AND uid='%s'", member_id, in["uid"].c_str());
        if (res != NULL && pgsql_num_rows(res) > 0) {
            map<const char*, const char*>f = pgsql_fetch_assoc(res, 0);
            CVars rec;
            map_to_cvars(f, rec);
            ret = PHP_API_OK;
            out["status"] = "OK";
            out = rec;
        }
        // LET SEE IF YOU HAVE NEXT DUE ITEM NOW
        out["next_due_status"] = "0";

      const PGresult *res2 = pgsql_query( "SELECT mj.contract AS item_code,mj.delivery_date AS due_date,mj.price,mj.client_id ,c.description AS currency "
                            " FROM members_jobs_contract mj "
                            " LEFT JOIN members_jobs j ON j.id = mj.job_id "
                            " LEFT JOIN currency c ON c.country=j.country "
                            " WHERE mj.member_id = %lu AND mj.status =1 AND mj.delivery_date > now() "
                            " UNION "
                            " SELECT mj.contract AS item_code,mj.delivery_date AS due_date,mj.price,mj.client_id ,c.description  AS currency "
                            " FROM members_jobs_contract mj "
                            " LEFT JOIN members_jobs j ON j.id = mj.job_id "
                            " LEFT JOIN currency c ON c.country=j.country "
                            " WHERE mj.client_id = %lu AND mj.status =1 AND mj.delivery_date > now() "
                            " ORDER BY due_date ASC",member_id,member_id);
                if (res2 != NULL && pgsql_num_rows(res2) > 0) {
                     out["next_due_status"] = "1";
                    map<const char*, const char*>f = pgsql_fetch_assoc(res2, 0);
                    CVars rec;
                    map_to_cvars(f, rec);
                    out["item_code"] = rec["item_code"];
                    out["due_date"]  = rec["due_date"];
                    out["price"]     = rec["price"];
                    out["currency"]  = rec["currency"];
                }

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

char *pin_generator(char *pin, int pin_length) {
  int base_number = 10;
  srand(time(0));
  for(int i = 0; i < pin_length; i++)
  {
    const char ch = 48 + (rand() % base_number);
    *(pin+i) = (char)ch;
  }
  return pin;
}

long WrenchResetMemberPass(CVars in, CVars &out) {
    logfmt(logINFO, "long WrenchResetMemberPass(CVars in, CVars out)");
    long ret = PHP_API_BAD_PARAM;
    const char * loc = getenv("REMOTE_ADDR");
    long member_id = 0;
    try {

        REQ_STRING(in, "email", 2, 49, "(.*)");
       // REQ_STRING(in, "rloc", 2, 15, "(.*)");
        //password_reset
        CVars yy;
        if (load_db_record(yy, "SELECT id AS member_id, uid AS member_uid FROM members WHERE username = '%s'", in["email"].c_str())) {
            member_id = yy["member_id"].Long();
        }

        char reset_pin[10]; // Please make sure there is enough space to hold the generated pin or you will get a "Segmentation fault" crash
        bzero(reset_pin, sizeof (reset_pin)); // Make it clean with zeroes or you likely to get a "Segmentation fault" crash on dirty RAM
        pin_generator(reset_pin, 5); // I am trying to generate 4 or 5 digits random numbers here

        CVars xx;
        if (member_id > 0) {
            int r1, r2, r3;
            char verify_link[100];
            srand(time(NULL));
            r1 = abs(rand()*100000000);
            xx["member_id"] = member_id;
            xx["member_id"].set_valid(true);
            xx["email"] = in["email"];
            xx["email"].set_valid(true);
            xx["loc"] = loc;
            xx["loc"].set_valid(true);
            xx["reset_pin"] = reset_pin;
            xx["reset_pin"].set_valid(true);


            out["password_reset_id"] = insert_db_record(DBS_VALID, "password_reset", "password_reset_id_seq", xx);

            if (out["password_reset_id"].Long() > 0) {
                in["password_reset_id"] = out["password_reset_id"];
                in["password_reset_id"].set_valid(true);
                pgsql_exec("UPDATE password_reset SET expired = now() + '1 day',pass_link=md5(now()::text)||''||md5(%d::text) WHERE id = %lu", r1, out["password_reset_id"].Long());
                account_email(ACCOUNT_PASSWORD_RESET, in, out);
                 if ( load_db_record(out, "SELECT uid AS reset_uid, id AS password_reset_id  FROM password_reset WHERE id = %lu  ",in["password_reset_id"].Long())> 0){
                    out["m_uid"]  = yy["member_uid"];
                    ret = PHP_API_OK;
                 }
            }
        }// if member_id
    } catch (bad_parameter) {
        out["log_status"] = "Invalid Password Reset Action";
    }
    logfmt(logINFO, "/long WrenchResetMemberPass(CVars in, CVars out)");
    return ret;
}

long LogWrenchBoardMember(CVars in, CVars &out) {

    logfmt(logINFO, "long LogWrenchBoardMember(CVars in, CVars out)");
    long ret = PHP_API_BAD_PARAM;
    const char * loc = getenv("REMOTE_ADDR");
    try {
        REQ_STRING(in, "mlog", 2, 149, "(.*)");
        REQ_LONG(in, "member_id", 1, -1);

        CVars xx;

        xx["member_id"] = in["member_id"];
        xx["member_id"].set_valid(true);
        xx["mlog"] = in["mlog"];
        xx["mlog"].set_valid(true);
        xx["loc"] = loc;
        xx["loc"].set_valid(true);

        out["request_id"] = insert_db_record(DBS_VALID, "members_log", "members_log_id_seq", xx);

    } catch (bad_parameter) {
        out["log_status"] = "Invalid Log Action";
    }
    logfmt(logINFO, "/long LogWrenchBoardMember(CVars in, CVars out)");


    return 0;
}

long LogManagerAction(CVars in, CVars &out) {

    logfmt(logINFO, "long LogManagerAction(CVars in, CVars out)");
    long ret = PHP_API_BAD_PARAM;
    try {
        REQ_STRING(in, "log_msg", 2, 149, "(.*)");
        OPTIONAL(in, "loc") REQ_STRING(in, "loc", 3, 15, "(.*)");
        REQ_LONG(in, "managers_id", 1, -1);

        CVars xx;

        xx["managers_id"] = in["managers_id"];
        xx["managers_id"].set_valid(true);
        xx["log_msg"] = in["log_msg"];
        xx["log_msg"].set_valid(true);
        xx["loc"] = in["loc"];
        xx["loc"].set_valid(true);

        out["request_id"] = insert_db_record(DBS_VALID, "managers_actions", "managers_actions_id_seq", xx);



    } catch (bad_parameter) {
        out["log_status"] = "Invalid Log Action";
    }
    logfmt(logINFO, "/long LogManagerAction(CVars in, CVars out)");


    return 0;
}

/* This return the list of jobs on the home page of the apps*/
long WrenchReturnPendingJobList(CVars in, CVars &out) {
    logfmt(logINFO, "WrenchReturnPendingJobList()");
    char vname[30];
    long ret = PHP_API_BAD_PARAM;

    try {
        long limit = REQ_LONG(in, "limit", 1, -1);
       // REQ_LONG(in, "page", 1, -1);
         REQ_LONG(in, "member_id", 1, -1);

        out["total_record"] = "0";

        const PGresult *res;
/*
 
         res = pgsql_query("SELECT j.title,j.description,m.job_id,m.expire "
                "FROM members_jobs_offer m "
                "LEFT JOIN members_jobs j ON j.id=m.job_id "
                "WHERE m.status = 1 AND m.client_id=0 "
                "AND m.expire IS NOT NULL "
                "AND  m.public_view = 1 "
                "ORDER BY m.expire DESC LIMIT %lu", in["limit"].Long());
 */


        res = pgsql_query("SELECT mo.member_id, to_char(mo.added, 'Dy Mon dd, yyyy HH:MI AM') AS  sent,"
                "  j.title,j.description,m.job_id,to_char( m.expire, 'Dy Mon dd, yyyy HH:MI AM') AS  expire, "
                "  c.code AS currency_code, c.description AS currency_description,j.country "
                "  FROM  members_offer_interest mo "
                "  LEFT JOIN  members_jobs_offer m ON m.id = mo.offer_id "
                "  LEFT JOIN members_jobs j ON j.id=m.job_id "
                "  LEFT JOIN currency c ON c.country=j.country "
                "  WHERE m.status = 1 AND m.client_id=0 "
                "  AND m.expire IS NOT NULL AND m.expire> now() AND  m.public_view = 1 "
                "  AND mo.member_id  = %lu  ORDER BY mo.added 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);

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

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

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

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

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

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

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

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


/* This return the list of jobs on the home page of the apps*/
long WrenchReturnStartJobList(CVars in, CVars &out) {
    logfmt(logINFO, "WrenchReturnStartJobList()");
    char vname[30];
    long ret = PHP_API_BAD_PARAM;

    try {
        long limit = REQ_LONG(in, "limit", 1, -1);
        REQ_LONG(in, "page", 1, -1);

        out["total_record"] = "0";

        const PGresult *res;

        res = pgsql_query("SELECT j.title,j.description,m.job_id,m.expire "
                "FROM members_jobs_offer m "
                "LEFT JOIN members_jobs j ON j.id=m.job_id "
                "WHERE m.status = 1 AND m.client_id=0 "
                "AND m.expire IS NOT NULL "
                "AND  m.public_view = 1 "
                "AND m.expire > now() "
                "ORDER BY m.expire DESC LIMIT %lu", 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);

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

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

                snprintf(vname, sizeof (vname), "expire_%05d", i);
                out[vname] = rec["expire"];
                
                snprintf(vname, sizeof (vname), "id_%05d", i);
                out[vname] = rec["job_id"];
            }
        }
        ret = PHP_API_OK;
        out["status"] = "OK";
    } catch (bad_parameter) {
        logfmt(logINFO, "ERROR CALL long medTrReasonList(CVars in, CVars &out)");
    }
    logfmt(logINFO, "/WrenchReturnStartJobList()");
    return ret;
}



long WrenchUpdateSiteGallery(CVars in, CVars &out) {
    long ret = PHP_API_BAD_PARAM;
    long member_id = REQ_LONG(in, "member_id", 1, -1);
    REQ_LONG(in, "gallery_type", 1, -1);
    OPTIONAL(in, "gallery") REQ_STRING(in, "gallery", 4, 150, "(.*)");
    const char * loc = getenv("REMOTE_ADDR");

    const PGresult *res = pgsql_query("SELECT id FROM members_site_gallery WHERE member_id=%lu AND gallery_type = %lu", in["member_id"].Long(), in["gallery_type"].Long());
    if (res != NULL && pgsql_num_rows(res) > 0) {
        pgsql_exec("UPDATE members_site_gallery SET gallery = '%s'  WHERE member_id=%ld AND id=%lu", in["gallery"].c_str(), in["member_id"].Long(), in["gallery_type"].Long());
        ret = PHP_API_OK;
        // NO WAY FOR DUPLICATE
    } else {
        CVars x;
        x["member_id"] = member_id;
        x["member_id"].set_valid(true);
        x["gallery"] = in["gallery"];
        x["gallery"].set_valid(true);
        x["loc"] = loc;
        x["loc"].set_valid(true);
        x["gallery_type"] = in["gallery_type"];
        x["gallery_type"].set_valid(true);
        long sid = insert_db_record(DBS_VALID, "members_site_gallery", "members_site_gallery_id_seq", x);
        ret = PHP_API_OK;
    }
    return ret;
}

long WrenchDeleteSaveSkill(CVars in, CVars &out) {
    logfmt(logINFO, "long WrenchDeleteSaveSkill(CVars in, CVars out)");
    long ret = PHP_API_BAD_PARAM;
    const char * loc = getenv("REMOTE_ADDR");
    long member_id = 0;

    try {

        long savedskill_id = REQ_LONG(in, "savedskill_id", 1, -1);
        long member_id = REQ_LONG(in, "member_id", 1, -1);

        CVars x;
        const PGresult *res = pgsql_query("SELECT * FROM members_skills WHERE member_id=%lu AND id=%lu ", in["member_id"].Long(), in["savedskill_id"].Long());

        if (res != NULL && pgsql_num_rows(res) > 0) {
            pgsql_exec("UPDATE members_skills SET status = 0  WHERE member_id=%ld AND id=%lu", in["member_id"].Long(), in["savedskill_id"].Long());
            ret = PHP_API_OK;
            // NO WAY FOR DUPLICATE
        } else {

        }


    } catch (bad_parameter) {
        out["log_status"] = "Invalid Log Action";
    }
    logfmt(logINFO, "/long WrenchDeleteSaveSkill(CVars in, CVars out)");
    return ret;




}

long WrenchSaveSkill(CVars in, CVars &out) {

    logfmt(logINFO, "long WrenchSaveSkill(CVars in, CVars out)");
    long ret = PHP_API_BAD_PARAM;
    const char * loc = getenv("REMOTE_ADDR");
    long member_id = 0;
    try {
        long category_id = REQ_LONG(in, "category_id", 1, -1);
        long skill_id = REQ_LONG(in, "skill_id", 1, -1);
        long member_id = REQ_LONG(in, "member_id", 1, -1);

        CVars x;
        const PGresult *res = pgsql_query("SELECT * FROM members_skills WHERE member_id=%lu AND skill_id=%lu AND category_id=%lu", in["member_id"].Long(), in["skill_id"].Long(), in["category_id"].Long());

        if (res != NULL && pgsql_num_rows(res) > 0) {
            // NO WAY FOR DUPLICATE
            // let us see the status
            map<const char*, const char*>f = pgsql_fetch_assoc(res, 0);
            //if (f.empty()) continue;
            CVars rec;
            map_to_cvars(f, rec);
            if (rec["status"].Long() == 0) {
                logfmt(logINFO, "~~~~~**** Update the status");
                pgsql_exec("UPDATE members_skills SET status = 1  WHERE status = 0 AND member_id=%ld AND id=%lu", in["member_id"].Long(), rec["id"].Long());
                ret = PHP_API_OK;

            }



        } else {
            CVars x;
            x["member_id"] = member_id;
            x["member_id"].set_valid(true);
            x["category_id"] = in["category_id"];
            x["category_id"].set_valid(true);
            x["skill_id"] = in["skill_id"];
            x["skill_id"].set_valid(true);
            long sid = insert_db_record(DBS_VALID, "members_skills", "members_skills_id_seq", x);
            ret = PHP_API_OK;
        }


    } catch (bad_parameter) {
        out["log_status"] = "Invalid Log Action";
    }
    logfmt(logINFO, "/long WrenchSaveSkill(CVars in, CVars out)");
    return ret;

}

long WrenchResetPass(CVars in, CVars &out) {

    logfmt(logINFO, "long WrenchResetMemberPass(CVars in, CVars out)");
    long ret = PHP_API_BAD_PARAM;
    const char * loc = getenv("REMOTE_ADDR");
    long member_id = 0;
    try {

        REQ_STRING(in, "pass_link", 10, 350, "(.*)");
        REQ_STRING(in, "newpass", 8, 15, "(.*)");

        CVars x;
        const PGresult *res = pgsql_query("SELECT * FROM password_reset WHERE expired>now() AND status = 0 AND pass_link='%s'", in["pass_link"].c_str());

        if (res != NULL && pgsql_num_rows(res) > 0) {
            map<const char*, const char*>f = pgsql_fetch_assoc(res, 0);
            //if (f.empty()) continue;
            CVars rec;
            map_to_cvars(f, rec);
            in["reset_id"] = rec["id"];
            in["reset_id"].set_valid(true);
            // good to go

            if (pgsql_exec("UPDATE members SET password  = md5('%s') WHERE id = %lu AND status = 1 ", in["newpass"].c_str(), rec["member_id"].Long())) {
                pgsql_exec("UPDATE password_reset SET status = 5  WHERE member_id=%ld AND pass_link='%s'", rec["member_id"].Long(), in["pass_link"].c_str());
                ret = PHP_API_OK;
                account_email(ACCOUNT_PASSWORD_COMPLT, in, out);
                out["status"] = "Completed";
            }
        } else {
            out["status"] = "Inavlid Process";
        }


    } catch (bad_parameter) {
        out["log_status"] = "Invalid Log Action";
    }
    logfmt(logINFO, "/long WrenchResetMemberPass(CVars in, CVars out)");


    return ret;


}


long WrenchUpdateAccountTerms(CVars in, CVars &out) {
    logfmt(logINFO, "long WrenchUpdateAccountTerms(CVars in, CVars out)");
    long ret = PHP_API_BAD_PARAM;
     out["terms_update"] = "";
    try {
        long action_item = REQ_LONG(in, "action_item", 1, -1);
        long member_id = REQ_LONG(in, "member_id", 1, -1);

        switch (action_item) {
            case ACCOUNT_AGREE_JOBS:
                pgsql_exec("UPDATE members SET post_jobs=NOW() WHERE id=%lu ", member_id);
                ret = PHP_API_OK;
                out["terms_update"] = "completed";
                break;

            case ACCOUNT_AGREE_REFER:
                pgsql_exec("UPDATE members SET refer=NOW() WHERE id=%lu ", member_id);
                ret = PHP_API_OK;
                 out["terms_update"] = "completed";
                break;
        }
    } catch (bad_parameter) {
        out["status"] = "Invalid Parameters";
    }
    logfmt(logINFO, "/long WrenchUpdateAccountTerms(CVars in, CVars out)");
    return ret;
}

long WrenchUpdateProfile(CVars in, CVars &out) {
    logfmt(logINFO, "long WrenchUpdateProfile(CVars in, CVars out) ******* RETIRE THIS FUNCTION - no country change");
    long ret = PHP_API_BAD_PARAM;
    try {
        REQ_STRING(in, "firstname", 3, 49, "(.*)");
        REQ_STRING(in, "lastname", 3, 49, "(.*)");
        REQ_STRING(in, "email", 5, 150, "(.*)");
        REQ_STRING(in, "state", 3, 150, "(.*)");
        REQ_STRING(in, "city", 3, 150, "(.*)");
        REQ_STRING(in, "country", 1, 3, "(.*)");
        long member_id = REQ_LONG(in, "member_id", 1, -1);
        CVars x;
        x["firstname"] = in["firstname"];
        x["firstname"].set_valid(true);
        x["lastname"] = in["lastname"];
        x["lastname"].set_valid(true);
        x["email"] = in["email"];
        x["email"].set_valid(true);
        x["state"] = in["state"];
        x["state"].set_valid(true);
        x["city"] = in["city"];
        x["city"].set_valid(true);
        x["country"] = in["country"];
        x["country"].set_valid(true);

        update_db_record(DBS_VALID, "members", x, member_id);
        ret = PHP_API_OK;


    } catch (bad_parameter) {
        out["status"] = "Invalid Parameters";
    }
    logfmt(logINFO, "/long WrenchUpdateProfile(CVars in, CVars out)");
    return ret;
}

long WrenchResendSendReferLoadLink(CVars in, CVars &out) {
    logfmt(logINFO, "long WrenchResendSendReferLoadLink(CVars in, CVars out)");
    long ret = PHP_API_BAD_PARAM;
    try {
        REQ_STRING(in, "uid", 3, 45, "(.*)");
		if (load_db_record(out, "SELECT id AS refer_id, * FROM members_refer_friend WHERE status<>5 AND uid ='%s'", in["uid"].c_str()) > 0)
		{
			const PGresult *res = pgsql_query("UPDATE members_refer_friend SET sent=now() WHERE uid='%s'", out["uid"].c_str());
            in["refer_id"] = out["refer_id"];
            in["refer_id"].set_valid(true);
            account_email(ACCOUNT_SEND_REFEREMAIL, in, out); 
            out["status"] = "Refer message sent";
            ret = PHP_API_OK;
		}

    } catch (bad_parameter) {
        out["status"] = "Invalid Parameters";
    }
    logfmt(logINFO, "/long WrenchResendSendReferLoadLink(CVars in, CVars out)");
    return ret;
}

long WrenchSendReferLoadLink(CVars in, CVars &out) {
    logfmt(logINFO, "long WrenchSendReferLoadLink(CVars in, CVars out)");
    long ret = PHP_API_BAD_PARAM;
    try {
        REQ_STRING(in, "refer_link", 3, 45, "(.*)");
		if (load_db_record(out, "SELECT uid FROM members_refer_friend WHERE updated IS NULL AND refer_link ='%s'", in["refer_link"].c_str()) > 0)
		{
		 const PGresult *res = pgsql_query("UPDATE members_refer_friend SET updated=now() WHERE uid='%s'", out["uid"].c_str());
		}

    } catch (bad_parameter) {
        out["status"] = "Invalid Parameters";
    }
    logfmt(logINFO, "/long WrenchSendReferLoadLink(CVars in, CVars out)");
    return ret;
}

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

    try {
        //out = in;
        out["status"] = "";
        REQ_STRING(in, "ref_firstname", 3, 49, "(.*)");
        REQ_STRING(in, "ref_lastname", 3, 49, "(.*)");
        REQ_STRING(in, "ref_email", 5, 150, "(.*)");
        long member_id = REQ_LONG(in, "member_id", 1, -1);

        const PGresult *res = pgsql_query("SELECT * FROM members_pending WHERE email='%s'", in["ref_email"].c_str());
        if (res != NULL && pgsql_num_rows(res) > 0) {
            out["status"] = "Unable to add this email";
            return ret;
        }

        const PGresult *res1 = pgsql_query("SELECT * FROM members WHERE email='%s'", in["ref_email"].c_str());
        if (res1 != NULL && pgsql_num_rows(res1) > 0) {
            out["status"] = "Unable to add this email";
            return ret;
        }

        const PGresult *res2 = pgsql_query("SELECT * FROM members_refer_friend WHERE email='%s' AND status IN (1,4,5)", in["ref_email"].c_str());
        if (res2 != NULL && pgsql_num_rows(res2) > 0) {
            out["status"] = "Unable to add this email";
            return ret;
        }

        CVars x;
        x["member_id"] = in["member_id"];
        x["member_id"].set_valid(true);
        x["firstname"] = in["ref_firstname"];
        x["firstname"].set_valid(true);
        x["email"] = in["ref_email"];
        x["email"].set_valid(true);
        x["lastname"] = in["ref_lastname"];
        x["lastname"].set_valid(true);

        int r1, r2, r3;
        char refer_link[100];
        srand(time(NULL));
        r1 = abs(rand()*100000000);
        srand(time(NULL));
        r2 = abs(rand() * r1);
        srand(time(NULL));
        r3 = abs(rand() * r2);
        sprintf(refer_link, "WRENREF-%09lu-%08lu-%08lu", r1, r2, r3);
        x["refer_link"] = refer_link;
        x["refer_link"].set_valid(true);
        long refer_id = 0;
        refer_id = insert_db_record(DBS_VALID, "members_refer_friend", "members_refer_friend_id_seq", x);

        if (refer_id > 0) {
			const PGresult *res4 = pgsql_query("UPDATE members_refer_friend SET sent=now() WHERE id=%lu", refer_id);
            in["refer_id"] = refer_id;
            in["refer_id"].set_valid(true);
            account_email(ACCOUNT_SEND_REFEREMAIL, in, out); // ALERT REFER EMAIL
            out["status"] = "Refer message sent";
            ret = PHP_API_OK;
        }
    } catch (bad_parameter) {
        out["status"] = "Invalid Parameters";
    }
    logfmt(logINFO, "/long WrenchSendRefer(CVars in, CVars out)");
    return ret;
}

/**************************************************************************************************************************/
long account_session_check(CVars in, CVars out) {
    logfmt(logINFO, "long account_session_check(CVars in, CVars out)");
    long ret = PHP_INVALID_SESSION;
    try {
        long session_expire_minutes = 15;
        in["session_expire_minutes"] = CfgReadChar("system.session_expire_minutes");
        session_expire_minutes = in["session_expire_minutes"].Long();

        REQ_STRING(in, "sessionid", 4, 140, "(.*)");
        OPTIONAL(in, "mode") REQ_LONG(in, "mode", 1, -1);
        if (in["mode"].Long() ==  900 ){
           if (load_db_record(out, "SELECT s.* FROM members_session s LEFT JOIN members m ON m.id=s.member_id "
                                    " WHERE  s.updated > (now() - interval '%lu minutes') "
                                    " AND s.session='%s'", session_expire_minutes, in["sessionid"].c_str()) > 0) {
                  pgsql_exec("UPDATE members_session SET updated=NOW() WHERE member_id=%ld AND session='%s'", in["sessionid"].c_str());
                ret = PHP_API_OK;
            }
        return ret;
        }
        long member_id = REQ_LONG(in, "member_id", 1, -1);
        if (load_db_record(out, "SELECT uid, member_id FROM members_session WHERE session='%s' AND member_id = %lu", in["sessionid"].c_str(),member_id) > 0) {
        CVars inx;
        inx["sessionid"] = in["sessionid"]; inx["sessionid"].set_valid( true );
        inx["member_id"] = out["member_id"]; inx["member_id"].set_valid( true );
            if (VerifySession(inx, out) == PHP_API_OK) {
                out["status"] = "Session valid";
                ret = PHP_API_OK;
            }
        }
    } catch (bad_parameter) {
        out["status"] = "Invalid session ID";
    }
    logfmt(logINFO, "/long account_session_check(CVars in, CVars out)");
    return ret;
}

/**************************************************************************************************************************/
long VerifySession(CVars in, CVars &out) {
    long ret = PHP_API_BAD_PARAM;
    logfmt(logINFO, "long SessionCheck(long uid, const char *sessionid, int create )");
    try {
        REQ_STRING(in, "sessionid", 4, 140, "(.*)");
        long member_id = REQ_LONG(in, "member_id", 1, -1);

       long session_expire_minutes = 15; // test build
       in["session_expire_minutes"] = CfgReadChar("system.session_expire_minutes");
       session_expire_minutes = in["session_expire_minutes"].Long();

        if (load_db_record(out, "SELECT s.* FROM members_session s LEFT JOIN members m ON m.id=s.member_id "
                                " WHERE s.member_id=%lu AND s.updated > (now() - interval '%lu minutes') AND s.session='%s'", member_id, session_expire_minutes, in["sessionid"].c_str()) > 0) {
            pgsql_exec("UPDATE members_session SET updated=NOW() WHERE member_id=%ld AND session='%s'", member_id, in["sessionid"].c_str());
            ret = PHP_API_OK;
        } else {
            // Clean old sessions
            pgsql_exec("DELETE FROM members_session WHERE member_id=%lu AND session='%s'", member_id, in["sessionid"].c_str());
            ret = PHP_API_BAD_PARAM;
        }
    } catch (bad_parameter) {
        out["status"] = "ERROR";
        ret = PHP_API_BAD_PARAM;
    }

    logfmt(logINFO, "/long SessionCheck(CVars in, CVars &out )");
    return ret; // No route
}

/**************************************************************************************************************************/
long SessionCheck(long uid, const char *sessionid, int create) {
    logfmt(logINFO, "long SessionCheck(long uid, const char *sessionid, int create )");
    // Sanity check
    if (uid < 1 || sessionid == NULL || strlen(sessionid) < 4) {
        return -1L; // Invalif parameters
    }
    CVars in;
    long session_expire_minutes = 15;
    in["session_expire_minutes"] = CfgReadChar("system.session_expire_minutes");
    session_expire_minutes = in["session_expire_minutes"].Long();

    // Clean old sessions
    pgsql_exec("DELETE FROM members_session WHERE member_id=%ld AND updated < (now() - interval '%lu minutes')", uid, session_expire_minutes);
    // Update/check existing session
    if (create == 0) {
        // do we still have this session
        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 Already deleted 
        }

        //Udate the session if you get here 
        pgsql_exec("UPDATE members_session SET updated=NOW() WHERE member_id=%ld AND session='%s'", uid, sessionid);
        return 1L; // Session updated
    }



    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 SessionCheck(long uid, const char *sessionid, int create )");
    return 0L; // No route
}

/*
CREATE TABLE mobile_login (
	id SERIAL,
	member_id INT REFERENCES members(id) UNIQUE NOT NULL,
	added timestamp without time zone DEFAULT now(),
    updated timestamp without time zone DEFAULT now()
	);
ALTER TABLE ONLY mobile_login
    ADD CONSTRAINT mobile_login_id_key UNIQUE (id);
*/
long  LoginLogger( long member_id, long login_mode){
	  CVars  sess;
	  long ret = 0;
	    try {
    		switch( login_mode ){
			case MOBILE_LOGIN:
					if (load_db_record(sess, "SELECT * FROM mobile_login WHERE member_id=%lu", member_id) > 0) {
					pgsql_exec("UPDATE mobile_login SET updated=NOW() WHERE member_id=%ld", member_id);
				}else{
					sess["member_id"] = member_id;
					sess["member_id"].set_valid(true);
					insert_db_record(DBS_VALID, "mobile_login", "mobile_login_id_seq", sess); //members_session_id_seq
				}		
			break;
		}
	
	
    } catch (bad_parameter) {
        ret = PHP_API_BAD_PARAM;
    }
    return ret;
}
/*
#define WEBSITE_LOGIN 1100
#define MOBILE_LOGIN 1101
#define FACEBOOK_LOGIN 1102
#define APPLE_LOGIN 1103
#define GOOGLE_LOGIN 1104
#define LOGIN_MODE_GENERAL     1100
#define LOGIN_MODE_FAMILY      1105
*/
//long LoginWrenchBoardFamilyLogin(CVars in, CVars &out);
//long WrenchBoardCreateFamilyAcc(CVars in, CVars &out);

long WrenchBoardFamilyAccMemberID(CVars in, CVars &out){
       long ret = PHP_API_BAD_PARAM;
       long family_member_id = 0;
       long parent_member_id = 0;
       long wallet_id = 0;
       logfmt(logINFO, "********~~~~~~~~ ------WrenchBoardFamilyAccMemberID()");
          try {

                      REQ_STRING(in, "family_uid", 5, 150, "(.*)");
                      const PGresult *res = pgsql_query(" SELECT member_id AS parent_member_id, id AS family_id,* FROM members_family "
                                                        " WHERE uid='%s'", in["family_uid"].c_str());
                      if (res != NULL && pgsql_num_rows(res) > 0) {
                          map<const char*, const char*>f = pgsql_fetch_assoc(res, 0);
                          CVars rec;
                          map_to_cvars(f, rec);
                          if( rec["family_member_id"]==""){
                             logfmt(logINFO, "LoginWrenchBoardFamilyLogin()- Need to Construct Account Now------->");
                             family_member_id = WrenchBoardCreateFamilyAcc(rec,out);
                          }
                          else{
                          family_member_id =rec["family_member_id"].Long();
                          }
                      }
                      else{
                       family_member_id = 0;
                      }

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

    return family_member_id;
}


long WrenchBoardCreateFamilyAcc(CVars in, CVars &out){
    long ret = 0;

          try {
                CVars x;
                    x["username"] = in["uid"];
                    x["username"].set_valid(true);
                    x["email"] = in["uid"];
                    x["email"].set_valid(true);
                    x["password"] = in["uid"];
                    x["password"].set_valid(true);
                    x["firstname"] = in["firstname"];
                    x["firstname"].set_valid(true);
                    x["lastname"] = in["lastname"];
                    x["lastname"].set_valid(true);
                    x["account_type"] = "FAMILY";
                    x["account_type"].set_valid(true);
                   // x["loc"] = out["loc"];
                   // x["loc"].set_valid(true);
                    ret = insert_db_record(DBS_VALID, "members", "members_id_seq", x); // family add

                    if ( ret > 0 ){
                        pgsql_exec("UPDATE members_family SET family_member_id=%lu WHERE uid='%s'",ret, in["uid"].c_str() );
                        load_db_record(out, "SELECT uid AS family_uid FROM members_family WHERE uid = '%s'", in["uid"].c_str());
                    }
            } catch (bad_parameter) {
                logfmt(logINFO, "ERROR CALL long WrenchBoardCreateFamilyAcc(CVars in, CVars &out)");
            }

    return ret;
}
long LoginWrenchBoardFamilyLogin(CVars in, CVars &out){

    long ret = PHP_API_BAD_PARAM;
    long family_member_id = 0;
    long parent_member_id = 0;
    long wallet_id = 0;
    logfmt(logINFO, "********~~~~~~~~ ------LoginWrenchBoardFamilyLogin()");

      try {
            REQ_STRING(in, "username", 5, 49, "(.*)");
            REQ_STRING(in, "pin", 4, 10, "(.*)");
            const PGresult *res = pgsql_query(" SELECT pm.uid AS parent_uid,  mf.member_id AS parent_member_id, mf.id AS family_id,*, mf.uid AS family_uid "
                                              " FROM members_family mf LEFT JOIN members pm ON mf.member_id = pm.id "
                                              " WHERE LOWER(mf.username)= LOWER('%s') AND mf.pin='%s' ", in["username"].c_str(),in["pin"].c_str());
            if (res != NULL && pgsql_num_rows(res) > 0) {
                map<const char*, const char*>f = pgsql_fetch_assoc(res, 0);
                CVars rec;
                map_to_cvars(f, rec);
                if( rec["family_member_id"]==""){
                   logfmt(logINFO, "LoginWrenchBoardFamilyLogin()- Need to Construct Account Now------->");
                   family_member_id = WrenchBoardCreateFamilyAcc(rec,out);

                }
                else{
                   family_member_id = rec["family_member_id"].Long();
                   parent_member_id = rec["parent_member_id"].Long();
                   out["family_uid"] = rec["family_uid"];
                }
                if (family_member_id > 0 && parent_member_id >  0){

                       load_db_record(out, "SELECT *,id AS member_id , to_char(last_login, 'Day Mon dd, yyyy HH:MI AM') AS last_login2 "
                                               " FROM members WHERE status=1 AND id = %lu",family_member_id);

                        out["parent_uid"] =  rec["parent_uid"]; // we need to join rooms
                        // default parent wallet based on country
                        CVars vw;
                        if( load_db_record(vw, "SELECT c.code AS currency from members m LEFT JOIN currency c ON c.country = m.country WHERE m.id=%lu AND m.country IS NOT NULL",parent_member_id)> 0 ){
                             logfmt(logINFO, "********~~~~~~~~ LoginWrenchBoardFamilyLogin() ------ CheckWallet() = %lu",parent_member_id);
                           // vw["currency"] = "NAIRA";  // this might become a variable based on the country
                            //vw["currency"].set_valid( true );
                            wallet_id = CheckWallet(out["member_id"].Long(),vw);
                            load_db_record( out, "SELECT amount AS balance FROM members_wallet WHERE member_id = %lu AND currency='%s' ", out["member_id"].Long(), vw["currency"].c_str());
                        }

                        pgsql_exec("DELETE FROM members_session WHERE member_id=%ld ", out["member_id"].Long());
                        // remove all existing session
                       load_db_record(in, "SELECT upper(md5(now()::text))||''|| upper(md5(now()::date::text)) AS sessionid");
                        if (SessionCheck(out["id"].Long(), in["sessionid"].c_str(), 1) > 0) {
                            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());
                            //===============================================================================================================================
                            pgsql_query("UPDATE members SET last_login = now()  WHERE id  = %lu", out["member_id"].Long());
                            // pgsql_query("UPDATE members SET last_login = now() , loc='%s' WHERE id  = %lu",loc, out["member_id"].Long());
                            pgsql_exec("UPDATE members_family SET last_login = now() WHERE family_member_id=%lu",family_member_id );
                            ret = PHP_LOGIN_OK;
                            LoginLogger(out["member_id"].Long(),LOGIN_MODE_FAMILY);
                        } else {
                            out["status"] = "Session check failed";
                        }
                 }
            }
    		out["status"] = "OK";
        } catch (bad_parameter) {
            logfmt(logINFO, "ERROR CALL long WrenchFamilyUpdate(CVars in, CVars &out)");
        }

    logfmt(logINFO, "********~~~~~~~~ LoginWrenchBoardFamilyLogin() ------ Completed() **** ");

return ret;
}


long LoginWrenchBoardAuxAccount(CVars in, CVars &out) {

    long login_channel = REQ_LONG(in, "login_channel", 1, -1);
    switch(login_channel){
        case LOGIN_GOOGLE:
            return LoginWrenchBoardGoogle(in, out);
        break;

        case LOGIN_FACEBOOK:
           return LoginWrenchBoardFacebook(in, out);
        break;

        case LOGIN_APPLE:
            return LoginWrenchBoardApple(in, out);
        break;
    }
return 0;
}

long LoginWrenchBoardQRAccount(CVars in, CVars &out) {
    /*
        $in['member_uid'] = $pieces[0];
        $in['member_username'] = $pieces[1];
        $in['family_uid'] = $pieces[2];
    */
    logfmt(logINFO, "LoginWrenchBoardQRAccount()");
    long ret = PHP_API_BAD_PARAM;
    try {
        // REQ_LONG( in, "whattodo", 1, -1 );
        REQ_STRING(in, "member_username", 5, 49, "(.*)");
        REQ_STRING(in, "member_uid", 5, 140, "(.*)");
        REQ_STRING(in, "family_uid", 4, 140, "(.*)");

        const PGresult* res = pgsql_query("SELECT f.username, f.pin FROM members_family f LEFT JOIN members m ON m.id=f.member_id  "
                          " WHERE f.uid = '%s' AND f.username = '%s' AND m.uid = '%s' ", in["family_uid"].c_str(), in["member_username"].c_str(), in["member_uid"].c_str());
        if (res != NULL && pgsql_num_rows(res) > 0) {
            map<const char*, const char*>f = pgsql_fetch_assoc(res,0);
            CVars rec;
            map_to_cvars(f, rec);
            CVars inx;
            inx["username"] = rec["username"];  inx["username"].set_valid( true );
            inx["pin"] = rec["pin"];  inx["pin"].set_valid( true );
            inx["login_mode"] = LOGIN_MODE_FAMILY;  inx["login_mode"].set_valid( true );
            return LoginWrenchBoardAccount(inx, out);
        }
        else{
          ret = PHP_API_BAD_PARAM;
        }

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

    logfmt(logINFO, "/LoginWrenchBoardQRAccount()");
    return ret;
}


long WrenchJobCount(long member_id){
    CVars out;
    long active_job_count = 0 ;
        if ( load_db_record(out, "SELECT count(id) AS active_job_count FROM members_jobs WHERE member_id=%lu AND status = 1",member_id)> 0 ){
             active_job_count = out["active_job_count"].Long();
        }
    return active_job_count;
}

long WrenchFamilyCount(long member_id){
    CVars out;
    long active_family_count = 0 ;
        if ( load_db_record(out, "SELECT count(id) AS active_job_count FROM members_family WHERE member_id=%lu AND status = 1",member_id)> 0 ){
             active_family_count = out["active_job_count"].Long();
        }
    return active_family_count;
}

long WrenchTestWalletCapability(CVars in, CVars &out){
  long ret = PHP_API_BAD_PARAM;
  out["wallet_available_status"] = "WALLET_NOT_AVAILABLE";
  out["wallet_country_status"] = "";
  out["wallet_action_type"]    = "";
  if (in["country"] == "" ){
     out["wallet_country_status"] = "USER_NEED_UPDATE_PROFILE_COUNTRY";
  }
  else{
      ret = load_db_record(out, "SELECT id AS wallet_id, action_type FROM currency WHERE country ='%s' LIMIT 1", in["country"].c_str());
      if ( ret >= 0 && out["wallet_id"].Long() > 0 ){
         out["wallet_available_status"] = "WALLET_AVAILABLE";
         out["wallet_country_status"]   = "USER_COUNTRY_WALLET_ENABLED";
         out["wallet_action_type"]      = out["action_type"];
      }
      else{
         out["wallet_country_status"] = "USER_COUNTRY_NOT_WALLET_ENABLED";
      }
  }
  return 0;
}

long LoginWrenchPromoAccount( CVars in, CVars &out ){
    long ret = PHP_API_BAD_PARAM;
    logfmt(logINFO, "LoginWrenchPromoAccount()");
    CVars x;
    CVars y;
    CVars p;
    CVars z;
    CVars inx;
    CVars inj;
    CVars outX;


        try {
            REQ_STRING(in, "promo_owner", 2, 149, "(.*)");
            REQ_STRING(in, "promo", 2, 49, "(.*)");
            REQ_STRING(in, "password", 8, 25, "(.*)");
            const char * loc = getenv("REMOTE_ADDR");

            load_db_record( p, "SELECT md5('%s') AS password_md5, 'NG' AS country ", in["password"].c_str());

            if ( load_db_record(y, "SELECT  firstname , lastname , middlename , status,email FROM market_import  WHERE uid::text ='%s' AND status = 1", in["promo_owner"].c_str())> 0){
                if ( load_db_record(out, "SELECT  id FROM members   WHERE LOWER(username)  = LOWER('%s')", y["email"].c_str())> 0){
                    out["status_message"] = "INVALID_LINK";
                    pgsql_query("UPDATE  market_import SET status = 4 WHERE uid::text = '%s' AND status = 1 ", in["promo_owner"].c_str());
                    return PHP_API_BAD_PARAM;
                }
                else
                {
                   out["status_message"] = "VALID_LINK_FOUND";
                }
            }
            else{
                   out["status_message"] = "VALID_LINK_NOT_FOUND";
                    return PHP_API_BAD_PARAM;
            }

                x["username"] = y["email"];
                x["username"].set_valid(true);
                x["firstname"] = y["firstname"];
                x["firstname"].set_valid(true);
                x["lastname"] = y["lastname"];
                x["lastname"].set_valid(true);
                x["email"] = y["email"];
                x["email"].set_valid(true);
                x["phone"] = y["phone"];
                x["phone"].set_valid(true);
                x["loc"] = loc;
                x["loc"].set_valid(true);
                x["country"] = p["country"];
                x["country"].set_valid(true);
                x["password"] = p["password_md5"];
                x["password"].set_valid(true);
                ret = insert_db_record(DBS_VALID, "members", "members_id_seq", x);


            if ( ret > 0 ){
                z["member_id"] = ret;
                z["member_id"].set_valid(true);
                WelcomeAccountMail(z);
                // let us mark tye import ac complete
                pgsql_query("UPDATE market_import SET status = 5 WHERE uid::text = '%s' AND status = 1 ", in["promo_owner"].c_str());

                inx["username"] = x["username"];  inx["username"].set_valid( true );
                inx["password"] = in["password"];  inx["password"].set_valid( true ); // before it was hashed
                inx["sessionid"] = "THIS-IS-DUMMY-INSURANCE";   inx["sessionid"].set_valid( true );
                inx["loc"] = loc;  inx["loc"].set_valid( true );
                inx["login_mode"] = LOGIN_MODE_GENERAL;  inx["login_mode"].set_valid( true );
                ret =  LoginWrenchBoardAccount(inx, out);
                logfmt(logINFO, "Auto Assign JOB LoginWrenchPromoAccount(CVars in, CVars &out)");

            if ( load_db_record(p, "SELECT  * FROM market_promo  WHERE promo::text ='%s' ", in["promo"].c_str())> 0){

                    if ( load_db_record(inj, "SELECT j.member_id, j.uid AS job_uid, j.id AS job_id, j.title,j.description,j.country, m.uid,j.job_detail "
                                             " FROM members_jobs j LEFT JOIN members m ON m.id = j.member_id WHERE j.uid::text ='%s'",p["first_job"].c_str())> 0){
                        // LEt us assign first task
                       // inj["member_id"] = "0";  inj["member_id"].set_valid( true );
                       // inj["uid"] = "0";  inj["uid"].set_valid( true );
                       // inj["job_id"] = "0";  inj["member_id"].set_valid( true );
                        //inj["job_uid"] = "0";  inj["member_id"].set_valid( true );
                        inj["promo"] = in["promo"];  inj["promo"].set_valid( true );
                        inj["strict_timeline"] = "10";  inj["strict_timeline"].set_valid( true );
                        inj["email"] = inx["username"] ;  inj["email"].set_valid( true );  // email
                        inj["job_description"] = inj["job_detail"];  inj["job_description"].set_valid( true );
                        inj["action"] = WRENCHBOARD_JOB_OFFER_SYSTEM;  inj["action"].set_valid( true );
                        inj["assign_mode"] = ASSIGN_MODE_EMAIL;  inj["assign_mode"].set_valid( true );
                        out["assign_id"] =  WrenchJobOfferSystems(inj, outX);
                    }

            }




                 /*



wrenchboard=> SELECT j.member_id, j.uid AS job_uid, j.id AS job_id, j.title,j.description,j.country, m.uid FROM members_jobs j LEFT JOIN members m ON m.id = j.member_id WHERE j.uid::text ='c127e9f6-fbae-4566-8753-3eb5138a500e';
 member_id |               job_uid                | job_id |              title               |                         description                         | country |                 uid
-----------+--------------------------------------+--------+----------------------------------+-------------------------------------------------------------+---------+--------------------------------------
       474 | c127e9f6-fbae-4566-8753-3eb5138a500e |    677 | Log in on the Android or IOS app | The task if to see what the app look like on on your device | NG      | c21d7d55-d24b-4cb0-a8e8-34362ef49d76
(1 row)





wrenchboard=> select uid,id from members_jobs where member_id =474;
                 uid                  | id
--------------------------------------+-----
 c127e9f6-fbae-4566-8753-3eb5138a500e | 677
 2dfd4c90-52fc-4d71-8589-0bbfd6eebd8e | 678
 89593568-4615-451e-9868-6682d514e44b | 679
 c32a7b17-4353-4e5e-bd75-44a45a71191e | 680

                    $data = array(
                        "member_id" => $member_id ,
                        "sessionid" => $session_id ,
                        "uid" => $uid,
                        "job_id" => '98',
                        "job_uid" => '473d3239-ecd7-4eb5-859c-78261720cb8e',
                        "email" => 'ses66181+3@gmail.com',
                        "job_description" => 'Nitetronic Z6 Anti Snoring Pillow, Best Snore Stopper Device, Clinically Proven Snoring Solution for Snorers, Smart Stop Snoring Technology Suitable for All Sleepers',
                        'action'=>WRENCHBOARD_JOB_OFFER_SYSTEM,
                        'assign_mode' => ASSIGN_MODE_EMAIL,
                    );
                 */

             //

            }


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

long LoginWrenchBoardAccount(CVars in, CVars &out) {
    long ret = PHP_API_BAD_PARAM;
    logfmt(logINFO, "LoginWrenchBoardAccount()");
    long login_mode = REQ_LONG(in, "login_mode", 1, -1);
    if( login_mode == LOGIN_MODE_FAMILY){
     logfmt(logINFO, "Login *WrenchBoard* Account Family Call***()");
      ret =  LoginWrenchBoardFamilyLogin(in, out);
      logfmt(logINFO, "LoginWrenchBoardFamilyLogin() ** Returned ** == >  %lu", ret);
      return ret;
    }

    REQ_STRING(in, "username", 5, 49, "(.*)");
    REQ_STRING(in, "password", 5, 49, "(.*)");
    REQ_STRING(in, "sessionid", 4, 140, "(.*)");
    OPTIONAL(in, "loc") REQ_STRING(in, "loc", 3, 15, "(.*)");
//  $in["login_mode"] = MOBILE_LOGIN; 
   // long login_mode = REQ_LONG(in, "login_mode", 0, -1);

    const char * loc = getenv("REMOTE_ADDR");
    in["loc"] = loc;
    in["loc"].set_valid(true);

    load_db_record(in, "SELECT upper(md5(now()::text))||''|| upper(md5(now()::date::text)) AS sessionid");
    ret = load_db_record(out, "SELECT *,id AS member_id , to_char(last_login, 'Day Mon dd, yyyy HH:MI AM') AS last_login2,country "
                              " FROM members WHERE status=1 AND "
                              " LOWER(username)=LOWER('%s') AND password= md5('%s')", in["username"].c_str(), in["password"].c_str());
    if (ret > 0) {
        out["wallet_status"] = "-1";
        if ( out["country"] !=""){
            out["wallet_status"] = "0";
            CVars vw;
            load_db_record(vw, "SELECT code AS currency FROM currency WHERE country='%s'",out["country"].c_str());
             if ( vw["currency"]  !=""){
                 vw["currency"].set_valid( true );
                 long wallet_id = CheckWallet(out["member_id"].Long(),vw);
                 load_db_record( out, "SELECT amount AS balance,amount AS default_wallet_balance FROM members_wallet WHERE member_id = %lu AND currency='%s' ", out["member_id"].Long(), vw["currency"].c_str()); // retired
                 out["wallet_status"] = "1";
             }
        }

        pgsql_exec("DELETE FROM members_session WHERE member_id=%ld ", out["member_id"].Long());
        // remove all existing session

        if (SessionCheck(out["id"].Long(), in["sessionid"].c_str(), 1) > 0) {
            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());
            //===============================================================================================================================
            pgsql_query("UPDATE members SET last_login = now() , loc='%s' WHERE id  = %lu",loc, out["member_id"].Long());
            account_email(ACCOUNT_LOGIN_ALERT, out, out); // ALERT CUSTOMER OF LOGIN
            ret = PHP_LOGIN_OK;

            CVars xout;
            if ( WrenchTestWalletCapability(out, xout) == 0 ){
            	out["wallet_country_status"]    = xout["wallet_country_status"];
            	out["wallet_available_status"]  = xout["wallet_available_status"];
            	out["wallet_action_type"]       = xout["wallet_action_type"];
            }

            in["member_id"] = out["member_id"];
            in["member_id"].set_valid(true);
            LoginWrenchBoardSetDashType(in, out);
            out["profile_pic_url"] = "https://www.wrenchboard.com/assets/images/profile.jpg";
            out["password"] = "";
            out["active_job_count"] = WrenchJobCount( out["member_id"].Long() );
            out["active_family_count"] = WrenchFamilyCount( out["member_id"].Long() );
            LoginLogger(out["member_id"].Long(),login_mode);
        } else {
            out["status"] = "Session check failed";
        }
    } else {
    // before we go -- may be sign up not completed
        ret = load_db_record(out, "SELECT id AS pending_id,uid AS pending_uid,username,country "
                                  " FROM members_pending WHERE status=1 "
                                  " AND LOWER(username)=LOWER('%s') AND expire>now() ", in["username"].c_str());
        if (ret > 0) {
            out["pending_status"] = "Pending signup found";
        }
        out["status"] = "Invalid username and/or password";
    }
    logfmt(logINFO, "/LoginWrenchBoardAccount()");
    return ret;
}

long LoginWrenchBoardSetDashType(CVars in, CVars &out){

    out["home_dash_type"] = "DEFAULT_HOME_DASH";
    out["family_action"] = "FAMILY_ACTION_NO_KIDS";

    /*
    DEFAULT_HOME_DASH
    FAMILY_PARENT_DASH
    WORKER_HOME_DASH
    JOBOWNER_HOME_DASH
    */


       /*
FAMILY_ACTION_NO_KIDS
FAMILY_ACTION_SEND_REWARD

  <app-fastreward  *ngIf="family_action=='FAMILY_ACTION_SEND_REWARD';"></app-fastreward>
  <app-familiy-nokids *ngIf="family_action=='FAMILY_ACTION_NO_KIDS';"></app-familiy-nokids>
  <app-familiy-notask  *ngIf="family_action=='FAMILY_ACTION_NO_TASKS';"></app-familiy-notask>
  <app-familiy-addfamily  *ngIf="family_action=='FAMILY_ACTION_ADD_FAMILY';"></app-familiy-addfamily>
  <app-familiy-allowancen  *ngIf="family_action=='FAMILY_ACTION_SETUP_ALLOWANCE';"></app-familiy-allowancen>
       */

    logfmt(logINFO, "LoginWrenchBoardSetDashType()");
    try {
       long member_id =  REQ_LONG(in, "member_id", 1, -1);
       // Job Owner Side ***********************************************************************************************
       if (  load_db_record(out, "SELECT count(id) AS pending_job_count FROM members_jobs_offer "
                                 " WHERE expire > now() AND member_id = %lu", in["member_id"].Long()) > 0 ){
         if ( out["pending_job_count"] > 0 ){
           out["home_dash_type"] = "JOBOWNER_HOME_DASH";
         return 0;
         }
       }

       if (  load_db_record(out, "SELECT count(id) AS contract_job_count FROM members_jobs_contract "
                                 " WHERE member_id = %lu AND status IN (1,2,3,4)", in["member_id"].Long()) > 0 ){
         if ( out["contract_job_count"] > 0 ){
           out["home_dash_type"] = "JOBOWNER_HOME_DASH";
         return 0;
         }
       }

       // Performing member ********************************************************************************************
       if (  load_db_record(out, "SELECT count(id) AS pending_job_count FROM members_jobs_offer "
                                 " WHERE expire > now() AND client_id = %lu", in["member_id"].Long()) > 0 ){
         if ( out["pending_job_count"] > 0 ){
           out["home_dash_type"] = "WORKER_HOME_DASH";
         return 0;
         }
       }

       if (  load_db_record(out, "SELECT count(id) AS contract_job_count FROM members_jobs_contract "
                                 " WHERE client_id = %lu AND status IN (1,2,3,4)", in["member_id"].Long()) > 0 ){
         if ( out["contract_job_count"] > 0 ){
           out["home_dash_type"] = "WORKER_HOME_DASH";
         return 0;
         }
       }

      // Now the family side *******************************************************************************************
       if (  load_db_record(out, "SELECT last_login, country, uid, added, (now() - added::date) AS age_days  "
                                 " FROM members WHERE id = %lu", in["member_id"].Long() ) >   0 ){
           if ( out["country"] == "US" ){
               out["home_dash_type"] = "FAMILY_PARENT_DASH";
               out["family_action"] = "FAMILY_ACTION_NO_KIDS";
                 if (  load_db_record(out, "SELECT count(id) AS family_count "
                                           " FROM members_family WHERE member_id = %lu", in["member_id"].Long() ) >   0 ){
                    if (out["family_count"].Long() > 0 ){
                       out["family_action"] = "FAMILY_ACTION_SEND_REWARD";
                       // check wallet
                       // check tasks
                        if (  load_db_record(out, "SELECT amount AS wbalance FROM members_wallet WHERE member_id = %lu AND currency =  'USD'",member_id) > 0 ){
                        if (out["wbalance"].Long() > 0 ){
                            out["family_action"] = "FAMILY_ACTION_NO_TASKS";
                          }
                        }

                    }
                 }
           }
       }

    }    catch (bad_parameter) {
        out["log_status"] = "Something went wrong with dash";
    }
  return 0;
}

long LoginWrenchBoardFacebook(CVars in, CVars &out) {
    long res = PHP_API_BAD_PARAM;
    logfmt(logINFO, "LoginWrenchBoardFacebook()");
    REQ_STRING(in, "fb_id", 5, 49, "(.*)");
		in["external_idp_provider_id"] = in["fb_id"].Long();
		in["external_idp_provider"] = 1L; // Facebook
		in["fb_id"].set_valid(false);
    REQ_STRING(in, "email", 6, 49, "(.*)");
    OPTIONAL(in, "firstname") REQ_STRING(in, "firstname", 1, 49, "(.*)");
    else in["firstname"] = "";
    OPTIONAL(in, "lastname") REQ_STRING(in, "lastname", 1, 49, "(.*)");
    else in["lastname"] = "";
    REQ_STRING(in, "sessionid", 4, 40, "(.*)");
    OPTIONAL(in, "loc") REQ_STRING(in, "loc", 3, 15, "(.*)");

       long retL = load_db_record(out, "SELECT uid, * FROM members WHERE LOWER(email)=LOWER('%s') AND password IS NOT NULL", in["email"].c_str());
        if (retL > 0 && out["uid"] !="") {
            out["status"] = "Email may be already registered, Try Login";
            return  PHP_API_BAD_PARAM;
        }

		res = LoginWrenchBoardExternal(in, out);
		logfmt(logINFO, "/LoginWrenchBoardFacebook()");
		return res;
}

long LoginWrenchBoardGoogle(CVars in, CVars &out) {
    long res = PHP_API_BAD_PARAM;
    logfmt(logINFO, "LoginWrenchBoardGoogle()");
    REQ_STRING(in, "google_id", 5, 49, "(.*)");
		in["external_idp_provider_id"] = in["google_id"].Long();
    in["external_idp_provider"] = 2L; // Google
		in["google_id"].set_valid(false);
    REQ_STRING(in, "email", 6, 49, "(.*)");
    OPTIONAL(in, "firstname") REQ_STRING(in, "firstname", 1, 49, "(.*)");
    else in["firstname"] = "";
    OPTIONAL(in, "lastname") REQ_STRING(in, "lastname", 1, 49, "(.*)");
    else in["lastname"] = "";
    REQ_STRING(in, "sessionid", 4, 40, "(.*)");
    OPTIONAL(in, "loc") REQ_STRING(in, "loc", 3, 15, "(.*)");

   long retL = load_db_record(out, "SELECT uid, * FROM members WHERE LOWER(email)=LOWER('%s') AND password IS NOT NULL", in["email"].c_str());
    if (retL > 0 && out["uid"] !="") {
        out["status"] = "Email may be already registered, Try Login";
        return  PHP_API_BAD_PARAM;
    }

    res = LoginWrenchBoardExternal(in, out);
    logfmt(logINFO, "/LoginWrenchBoardGoogle()");
    return res;
}

long LoginWrenchBoardApple(CVars in, CVars &out) {
    long res = PHP_API_BAD_PARAM;
    logfmt(logINFO, "LoginWrenchBoardApple()");
    REQ_STRING(in, "apple_id", 5, 49, "(.*)");
		in["external_idp_provider_id"] = in["apple_id"];
    in["external_idp_provider"] = 3L; // Apple
		in["apple_id"].set_valid(false);
    REQ_STRING(in, "email", 6, 49, "(.*)");
    OPTIONAL(in, "firstname") REQ_STRING(in, "firstname", 1, 49, "(.*)");
    else in["firstname"] = "";
    OPTIONAL(in, "lastname") REQ_STRING(in, "lastname", 1, 49, "(.*)");
    else in["lastname"] = "";
    REQ_STRING(in, "sessionid", 4, 40, "(.*)");
    OPTIONAL(in, "loc") REQ_STRING(in, "loc", 3, 15, "(.*)");

       long retL = load_db_record(out, "SELECT uid, * FROM members WHERE LOWER(email)=LOWER('%s') AND password IS NOT NULL", in["email"].c_str());
        if (retL > 0 && out["uid"] !="") {
            out["status"] = "Email may be already registered, Try Login";
            return  PHP_API_BAD_PARAM;
        }
    res = LoginWrenchBoardExternal(in, out);
    logfmt(logINFO, "/LoginWrenchBoardApple()");
    return res;
}

long LoginWrenchBoardExternal(CVars in, CVars &out) {
    long res = PHP_API_BAD_PARAM;
		logfmt(logINFO, "LoginWrenchBoardExternal()");
		const char * loc = getenv("REMOTE_ADDR");
    in["loc"] = loc;
    in["loc"].set_valid(true);

    long ret = load_db_record(out, "SELECT * FROM members WHERE LOWER(email)=LOWER('%s') AND password IS NOT NULL", in["email"].c_str());
    if (ret > 0) {
        out["status"] = "Email is already registered";
    } else {
        load_db_record(in, "SELECT upper(md5(now()::text))||''|| upper(md5(now()::date::text)) AS sessionid");
        ret = load_db_record(out, "SELECT *,id AS member_id FROM members WHERE LOWER(email)=LOWER('%s') AND external_idp_provider_id='%s' AND external_idp_provider=%ld", in["email"].c_str(), in["external_idp_provider_id"].c_str(), in["external_idp_provider"].Long());
        if (ret > 0) {
            logfmt(logINFO, "External account already exists");
        } else {

            logfmt(logINFO, "Create new FB account");
            CVars xx;
            xx["username"] = in["email"];
            xx["username"].set_valid(true);
            xx["firstname"] = in["firstname"];
            xx["firstname"].set_valid(true);
            xx["lastname"] = in["lastname"];
            xx["lastname"].set_valid(true);
            xx["email"] = in["email"];
            xx["email"].set_valid(true);
            xx["loc"] = in["loc"];
            xx["loc"].set_valid(true);
						xx["external_idp_provider"] = in["external_idp_provider"];
						xx["external_idp_provider"].set_valid(true);
            xx["external_idp_provider_id"] = in["external_idp_provider_id"];
            xx["external_idp_provider_id"].set_valid(true);
            out["member_id"] = insert_db_record(DBS_VALID, "members", "members_id_seq", xx);
            ret = load_db_record(out, "SELECT *,id AS member_id,country FROM members WHERE id='%ld'", out["member_id"].Long());
        }
        if (out["member_id"].Long() > 0) {
           out["wallet_status"] = "-1";
            if ( out["country"] !=""){  // need to construct wallet if needed.
                out["wallet_status"] = "0";
                CVars vw;
                load_db_record(vw, "SELECT code AS currency FROM currency WHERE country='%s'",out["country"].c_str());
                 if ( vw["currency"]  !=""){
                     //vw["currency"] = "NAIRA";  // this might become a variable based on the country
                     vw["currency"].set_valid( true );
                     long wallet_id = CheckWallet(out["member_id"].Long(),vw);
                     load_db_record( out, "SELECT amount AS balance,amount AS default_wallet_balance FROM members_wallet WHERE member_id = %lu AND currency='%s' ", out["member_id"].Long(), vw["currency"].c_str()); // retired
                     out["wallet_status"] = "1";
                 }
            }

            pgsql_exec("DELETE FROM members_session WHERE member_id=%ld ", out["member_id"].Long());
            // remove all existing session	
            if (SessionCheck(out["id"].Long(), in["sessionid"].c_str(), 1) > 0) {
                out["stauts"] = "OK";
                pgsql_query("UPDATE members SET last_login = now() WHERE id  = %lu", out["member_id"].Long());
                /*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());
                //===============================================================================================================================
                account_email(ACCOUNT_LOGIN_ALERT, out, out); // ALERT CUSTOMER OF LOGIN
                out["profile_pic_url"] = "https://www.wrenchboard.com/assets/images/profile.jpg";
                out["active_job_count"] = WrenchJobCount( out["member_id"].Long() );
                out["active_family_count"] = WrenchFamilyCount( out["member_id"].Long() );
                res = PHP_LOGIN_OK;
            } else {
                out["status"] = "Session check failed";
            }
        }
    }
    logfmt(logINFO, "/LoginWrenchBoardExternal()");
    return res;
}



//******************************************************************************

long AddMobileTopuNumber(CVars in, CVars &out) {
    long ret = -1;
    long pin = REQ_LONG(in, "pin", 1, -1);
    long customer_id = REQ_LONG(in, "customer_id", 1, -1);
    OPTIONAL(in, "loc") REQ_STRING(in, "loc", 3, 15, "(.*)");
    REQ_STRING(in, "seller_number", 10, 11, "(.*)");

    CVars x;
    x["pin"] = in["pin"];
    x["pin"].set_valid(true);
    x["customer_id"] = in["customer_id"];
    x["customer_id"].set_valid(true);
    x["loc"] = in["loc"];
    x["loc"].set_valid(true);
    x["seller_number"] = in["seller_number"];
    x["seller_number"].set_valid(true);

    ret = insert_db_record(DBS_VALID, "mobile_sales_auth", "mobile_sales_auth_id_seq", x);

    out["status"] = ret;
    out["auth_id"] = ret;



    return ret;
}


//******************************************************************************

long InitiateAddCustomerBalance(CVars in, CVars &out) {
    logfmt(logINFO, "AddCustomerBalance()");
    long ret = PHP_API_BAD_PARAM;
    try {
        // REQ_LONG( in, "whattodo", 1, -1 );



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

    logfmt(logINFO, "/AddCustomerBalance()");
    return ret;
}

long CompleteAddCustomerBalance(CVars in, CVars &out) {
    logfmt(logINFO, "AddCustomerBalance()");
    long ret = PHP_API_BAD_PARAM;
    try {
        // REQ_LONG( in, "whattodo", 1, -1 );



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

    logfmt(logINFO, "/AddCustomerBalance()");
    return ret;
}

//******************************************************************************




//******************************************************************************

long VerifyEmailWrenchBoardAccount(CVars in, CVars &out) {
    logfmt(logINFO, "VerifyEmailWrenchBoardAccount()");
    long ret = PHP_API_BAD_PARAM;
    try {
        long account_id = REQ_LONG(in, "account_id", 1, -1);
        //  ret = load_db_record( out, "SELECT * FROM members WHERE id = %lu", account_id );


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

    logfmt(logINFO, "/VerifyEmailWrenchBoardAccount()");
    return ret;
}
//******************************************************************************

long VerifyPhoneWrenchBoardAccount(CVars in, CVars &out) {
    logfmt(logINFO, "VerifyPhoneWrenchBoardAccount()");
    long ret = PHP_API_BAD_PARAM;
    try {
        // REQ_LONG( in, "whattodo", 1, -1 );



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

    logfmt(logINFO, "/VerifyPhoneWrenchBoardAccount()");
    return ret;
}
//******************************************************************************

long EditProfileWrenchBoardAccount(CVars in, CVars &out) {
    logfmt(logINFO, "EditProfileWrenchBoardAccount()");
    long ret = PHP_API_BAD_PARAM;
    try {
        long account_id = REQ_LONG(in, "account_id", 1, -1);
        REQ_STRING(in, "State", 2, 20, "(.*)");
        REQ_STRING(in, "Zipcode", 3, 15, "(.*)");
        REQ_STRING(in, "Country", 2, 5, "(.*)");



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

    logfmt(logINFO, "/EditProfileWrenchBoardAccount()");
    return ret;
}
//******************************************************************************

long LoadProfileWrenchBoardAccount(CVars in, CVars &out) {
    logfmt(logINFO, "LoadProfileWrenchBoardAccount()");
    long ret = PHP_API_BAD_PARAM;
    try {
        long account_id = REQ_LONG(in, "account_id", 1, -1);
        const PGresult* res = pgsql_query("SELECT * FROM members WHERE id = %lu", account_id);
        if (res && pgsql_num_rows(res) > 0) {
        }

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

    logfmt(logINFO, "/LoadProfileWrenchBoardAccount()");
    return ret;
}
//******************************************************************************
//*****************************************************************************/

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

        out["etisalat_endpoint"] = "http://etisalat.service.chiefsoft.com/etisalat_payquic.php";


        ret = PHP_API_OK;

    } catch (bad_parameter) {

        out["status"] = "Bad parameter";

    } catch (...) {

        out["status"] = "Unhandled exception in INTW_configure";

    }
    logfmt(logINFO, "/long ETSL_configure(CVars in, CVars &out)");
    return ret;
}

long DeliverMobilseEtisalat(CVars in, CVars &out) {
    logfmt(logINFO, "long INTW_sendBillPaymentAdvice(CVars in, CVars &out)");
    long ret = PHP_API_BAD_PARAM;
    try {
        int customerId = REQ_LONG(in, "customerid", 1, -1);
        int paymentItemId = REQ_LONG(in, "paymentitemid", 1, -1);
        int amount = REQ_LONG(in, "amount", 0, -1);

        REQ_STRING(in, "customermobile", 5, 15, "(.*)");
        OPTIONAL(in, "customeremail") REQ_STRING(in, "customeremail", 1, 100, "(.*)");
        OPTIONAL(in, "order_id") REQ_STRING(in, "order_id", 1, 25, "(.*)");
        char CustomerMobile[15];
        char CustomerEmail[100];





        sprintf(CustomerEmail, "%s", in["customeremail"].c_str());
        sprintf(CustomerMobile, "%s", in["customermobile"].c_str());


        //topalert = "sales@payquic.com";
        out["topalert"] = CfgReadChar("transnotif.topalert");
        sprintf(CustomerEmail, "%s", out["topalert"].c_str());


        CVars customer; // Load customer
        ret = load_db_record(customer, "SELECT email,firstname,lastname FROM customer WHERE status=1 AND id = %lu", customerId);
        if (ret < 1L) {
            throw new bad_parameter(out, "customerid");
        }

        CVars paymentitem; // Load payment item
        ret = load_db_record(paymentitem, "SELECT id,billerid,billername,name,amount,paymentcode FROM interswitch_biller_payment_items WHERE gid = %lu", paymentItemId);
        if (ret < 1L) {
            out["advice"] = "PaymentID not found or not valid !!!";
            throw new bad_parameter(out, "paymentitemid");
        }

        // Check amount
        if (amount < 1L) {
            amount = paymentitem["amount"].Long();
        }






        // Create record
        CVars advice;

        advice["customerid"] = customerId;
        advice["customerid"].set_valid(true);
        advice["billerid"] = paymentitem["billerid"];
        advice["billerid"].set_valid(true);
        advice["billerpaymentitemgid"] = paymentItemId;
        advice["billerpaymentitemgid"].set_valid(true);
        advice["amount"] = amount;
        advice["amount"].set_valid(true);
        advice["paymentcode"] = paymentitem["paymentcode"];
        advice["paymentcode"].set_valid(true);
        advice["order_id"] = in["order_id"];
        advice["order_id"].set_valid(true);
        advice["customeremail"] = in["customeremail"];
        advice["customeremail"].set_valid(true);
        advice["customermobile"] = in["customermobile"];
        advice["customermobile"].set_valid(true);

        out["bill_payment_advice_id"] = insert_db_record(DBS_VALID, "interswitch_bill_payment_advice", "interswitch_bill_payment_advice_id_seq", advice);
        if (out["bill_payment_advice_id"].Long() < 1L) {
            //throw new runtime_error("Failed to create interswitch bill payment advice record");
            return PHP_API_BAD_PARAM;
        }

        // Initiate interswitch session
        CVars setup;
        ETSL_configure(in, setup);



        CVars transaction;



        transaction["detail_id"] = out["bill_payment_advice_id"];
        transaction["detail_id"].set_valid(true);
        transaction["type"] = 1L;
        /* SendBillPaymentAdvice */ transaction["type"].set_valid(true);
        out["transaction_id"] = insert_db_record(DBS_VALID, "interswitch_transaction", "interswitch_transaction_id_seq", transaction);
        if (out["transaction_id"].Long() < 1L) {
            //	throw new runtime_error("Failed to create interswitch transaction record");
            return PHP_API_BAD_PARAM;
        }


        char uniqueRef[20];
        memset(uniqueRef, 0, 20);
        // TransferCode - RequestReference - UniqueRef => request prefix for terminal owner + ID
        sprintf(uniqueRef, "ETSL%08lu", out["transaction_id"].Long());
        //sprintf( uniqueRef, "%s%09s", setup["interswitch_pfix"].c_str(), out["transaction_id"].c_str() );
        transaction["transfer_code"] = uniqueRef;
        transaction["transfer_code"].set_valid(true);

        CVars cxc;
        cxc["transfer_code"] = transaction["transfer_code"];
        cxc["transfer_code"].set_valid(true);
        update_db_record(DBS_VALID, "interswitch_transaction", cxc, out["transaction_id"].Long());
        logfmt(logINFO, "Here -> 1");
        logfmt(logINFO, "SENDING TRANSACTION - setup[interswitch_tid].c_str() ->%s", setup["interswitch_tid"].c_str());
        // Prepare call
        const int statusSize = 1024;
        char status[statusSize];
        char transactionRef[statusSize];
        memset(status, 0, statusSize); // Clear?
        memset(transactionRef, 0, statusSize); // Clear?

        char xtid[12];

        sprintf(xtid, "%s", setup["interswitch_tid"].c_str());

        logfmt(logINFO, "SENDING PAQUIC ETISALAT TRANSACTION->%s", xtid);
        out["ResponseCode"] = "99999";
        long ret1 = GateDeliverMobilseEtisalat(in, out);

        if (out["statusCode"].Long() == 0 && out["errorCode"].Long() == 0) {
            ret = 90000L;
            //'message' => '<?xml version="1.0" encoding="utf-8"?><result><statusCode>0</statusCode><errorCode>0</errorCode><errorDescription>Successful Transaction 0305055755074473</errorDescription><instanceId>0305055755074473</instanceId></result>'

            try {
                CVars txt;
                txt["responsecode"] = "90000";
                txt["responsecode"].set_valid(true);
                txt["transactionref"] = out["errorDescription"];
                txt["transactionref"].set_valid(true);
                update_db_record(DBS_VALID, "interswitch_transaction", txt, out["transaction_id"].Long());
            } catch (...) {
                out["status"] = "I see no good response from interswitch";
            }

            CVars fr0;
            fr0["status"] = "5";
            fr0["status"].set_valid(true);
            update_db_record(DBS_VALID, "interswitch_bill_payment_advice", fr0, out["bill_payment_advice_id"].Long());

        } else {

            try {
                CVars txt0;
                txt0["responsecode"] = "99999";
                txt0["responsecode"].set_valid(true);
                txt0["transactionref"] = out["errorDescription"];
                txt0["transactionref"].set_valid(true);
                update_db_record(DBS_VALID, "interswitch_transaction", txt0, out["transaction_id"].Long());
            } catch (...) {
                out["status"] = "I see no good response from interswitch";
            }

            CVars fr1;
            fr1["status"] = "7";
            fr1["status"].set_valid(true);
            update_db_record(DBS_VALID, "interswitch_bill_payment_advice", fr1, out["bill_payment_advice_id"].Long());
        }

        out["statusCode"].set_valid(true);


    } catch (bad_parameter) {
        out["status"] = "Incorrect parameter";
        ret = PHP_API_BAD_PARAM;
    } catch (...) {
        out["status"] = "Unhandled exception in INTW_sendBillPaymentAdvice";
    }
    logfmt(logINFO, "/long INTW_sendBillPaymentAdvice(CVars in, CVars &out)");
    return ret;



}

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

    CURL *curl;
    CURLcode res;

    struct MemoryStruct chunk;

    chunk.memory = (char*) malloc(1); /* will be grown as needed by the realloc above */
    chunk.size = 0; /* no data at this point */

    curl_global_init(CURL_GLOBAL_ALL);

    /* get a curl handle */
    curl = curl_easy_init();

    if (curl) {
        // Prepare data
        string data = "";
        CVars::iterator i;
        int j = 0; // Will limit to 200 variables
        for (i = in.begin(); i != in.end() && j < 200; i++) {
            logfmt(logINFO, "IN: %s=%s", i->first.c_str(), i->second.c_str());
            if (j > 0) {
                data += "&";
            }
            data += i->first.c_str();
            data += "=";
            data += i->second.c_str();
            j++;
        }
        logfmt(logINFO, "DATA: %s", data.c_str());
        curl_easy_setopt(curl, CURLOPT_URL, "http://etisalat.service.chiefsoft.com/etisalat_payquic.php");
        curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data.c_str());
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *) &chunk);
        res = curl_easy_perform(curl);
        if (res != CURLE_OK) {
            // Error
            out["status"] = curl_easy_strerror(res);
            logfmt(logINFO, "ERROR: %s", out["status"].c_str());
            ret = PHP_API_BAD_PARAM;
        } else {
            logfmt(logINFO, "%lu bytes retrieved\n", (long) chunk.size);
            data = (const char *) chunk.memory;
            istringstream buffer(data);
            string temp, key, val;
            size_t found;
            while (std::getline(buffer, temp)) {
                logfmt(logINFO, "line: %s", temp.c_str());
                found = temp.find_first_of("=");
                key = temp.substr(0, found);
                val = temp.substr(found + 1);
                out[key] = base64_decode(val);
                logfmt(logINFO, "'%s' => '%s'", key.c_str(), out[key].c_str());
            }
            ret = PHP_API_OK;
        }
        curl_easy_cleanup(curl);

        if (chunk.memory) {
            free(chunk.memory);
        }
    }
    curl_global_cleanup();
    logfmt(logINFO, "/long DeliverMobilseEtisalat(CVars in, CVars &out)");
    return ret;
}

/*
void TeleSignAddJob(const char *CustomerId, const char *AutheticationId, const char *CountryCode, const char *PhoneNumber, const char *PIN) { 
  // I make sure that headerlist is erased before rebuilding it with the soap function 
  curl_slist_free_all(headerlist); 
  headerlist = curl_slist_append(headerlist, "Host: www.telesign.com");
  headerlist = curl_slist_append(headerlist, "Content-Type: text/xml"); 
  headerlist = curl_slist_append(headerlist, "SOAPAction: \"https://www.telesign.com/api/RequestCALL\""); 
  sprintf(TeleSignSoapReq, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\
<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" \
xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">\
  <soap:Body>\
    <RequestCALL xmlns=\"https://www.telesign.com/api/\">\
      <CustomerID>%s</CustomerID>\
      <AuthenticationID>%s</AuthenticationID>\
      <CountryCode>%s</CountryCode>\
      <PhoneNumber>%s</PhoneNumber>\
      <VerificationCode>%s</VerificationCode>\
      <RedialCount>1</RedialCount>\
    </RequestCALL>\
</soap:Body>\
</soap:Envelope>", CustomerId, AutheticationId, CountryCode, PhoneNumber, PIN); 
        //FILE_LOG(logINFO) << TeleSignSoapReq;
  curl_easy_setopt(ch, CURLOPT_POSTFIELDS, TeleSignSoapReq); 
  curl_easy_setopt(ch, CURLOPT_HTTPHEADER, headerlist); 
  curl_easy_perform(ch); 
} 
 */
/*
 * vi:ts=2
 */
