function rent($userId, $bike, $force = FALSE)
{
    global $db, $forcestack, $watches, $credit;
    $stacktopbike = FALSE;
    $bikeNum = $bike;
    $requiredcredit = $credit["min"] + $credit["rent"] + $credit["longrental"];
    $creditcheck = checkrequiredcredit($userId);
    if ($creditcheck === FALSE) {
        response(_('You are below required credit') . " " . $requiredcredit . $credit["currency"] . ". " . _('Please, recharge your credit.'), ERROR);
    }
    checktoomany(0, $userId);
    $result = $db->query("SELECT count(*) as countRented FROM bikes where currentUser={$userId}");
    $row = $result->fetch_assoc();
    $countRented = $row["countRented"];
    $result = $db->query("SELECT userLimit FROM limits where userId={$userId}");
    $row = $result->fetch_assoc();
    $limit = $row["userLimit"];
    if ($countRented >= $limit) {
        if ($limit == 0) {
            response(_('You can not rent any bikes. Contact the admins to lift the ban.'), ERROR);
        } elseif ($limit == 1) {
            response(_('You can only rent') . " " . sprintf(ngettext('%d bike', '%d bikes', $limit), $limit) . " " . _('at once') . ".", ERROR);
        } else {
            response(_('You can only rent') . " " . sprintf(ngettext('%d bike', '%d bikes', $limit), $limit) . " " . _('at once and you have already rented') . " " . $limit . ".", ERROR);
        }
    }
    if ($forcestack or $watches["stack"]) {
        $result = $db->query("SELECT currentStand FROM bikes WHERE bikeNum='{$bike}'");
        $row = $result->fetch_assoc();
        $standid = $row["currentStand"];
        $stacktopbike = checktopofstack($standid);
        if ($watches["stack"] and $stacktopbike != $bike) {
            $result = $db->query("SELECT standName FROM stands WHERE standId='{$standid}'");
            $row = $result->fetch_assoc();
            $stand = $row["standName"];
            $user = getusername($userId);
            notifyAdmins(_('Bike') . " " . $bike . " " . _('rented out of stack by') . " " . $user . ". " . $stacktopbike . " " . _('was on the top of the stack at') . " " . $stand . ".", ERROR);
        }
        if ($forcestack and $stacktopbike != $bike) {
            response(_('Bike') . " " . $bike . " " . _('is not rentable now, you have to rent bike') . " " . $stacktopbike . " " . _('from this stand') . ".", ERROR);
        }
    }
    $result = $db->query("SELECT currentUser,currentCode FROM bikes WHERE bikeNum={$bikeNum}");
    $row = $result->fetch_assoc();
    $currentCode = sprintf("%04d", $row["currentCode"]);
    $currentUser = $row["currentUser"];
    $result = $db->query("SELECT note FROM notes WHERE bikeNum='{$bikeNum}' ORDER BY time DESC");
    $note = "";
    while ($row = $result->fetch_assoc()) {
        $note .= $row["note"] . "; ";
    }
    $note = substr($note, 0, strlen($note) - 2);
    // remove last two chars - comma and space
    $newCode = sprintf("%04d", rand(100, 9900));
    //do not create a code with more than one leading zero or more than two leading 9s (kind of unusual/unsafe).
    if ($currentUser == $userId) {
        response(_('You have already rented the bike') . ' ' . $bikeNum . '. ' . _('Code is') . ' <span class="label label-primary">' . $currentCode . '</span>. ' . _('Return bike by scanning QR code on a stand') . '.', ERROR);
        return;
    }
    if ($currentUser != 0) {
        response(_('Bike') . " " . $bikeNum . " " . _('is already rented') . ".", ERROR);
        return;
    }
    $message = '<h3>' . _('Bike') . ' ' . $bikeNum . ': <span class="label label-primary">' . _('Open with code') . ' ' . $currentCode . '.</span></h3>' . _('Change code immediately to') . ' <span class="label label-default">' . $newCode . '</span><br />' . _('(open, rotate metal part, set new code, rotate metal part back)') . '.';
    if ($note) {
        $message .= "<br />" . _('Reported issue:') . " <em>" . $note . "</em>";
    }
    $result = $db->query("UPDATE bikes SET currentUser={$userId},currentCode={$newCode},currentStand=NULL WHERE bikeNum={$bikeNum}");
    $result = $db->query("INSERT INTO history SET userId={$userId},bikeNum={$bikeNum},action='RENT',parameter={$newCode}");
    response($message);
}
function note($number, $bikeNum, $message)
{
    global $db;
    $userId = getUser($number);
    $bikeNum = trim($bikeNum);
    if (preg_match("/^[0-9]*\$/", $bikeNum)) {
        $bikeNum = intval($bikeNum);
    } else {
        if (preg_match("/^[A-Z]+[0-9]*\$/i", $bikeNum)) {
            $standName = $bikeNum;
            standnote($number, $standName, $message);
            return;
        } else {
            sendSMS($number, _('Error in bike number / stand name specification:' . $db->conn->real_escape_string($bikeNum)));
            return;
        }
    }
    $bikeNum = intval($bikeNum);
    $result = $db->query("SELECT number,userName,stands.standName FROM bikes LEFT JOIN users on bikes.currentUser=users.userID LEFT JOIN stands on bikes.currentStand=stands.standId where bikeNum={$bikeNum}");
    if ($result->num_rows != 1) {
        sendSMS($number, _('Bike') . " " . $bikeNum . " " . _('does not exist') . ".");
        return;
    }
    $row = $result->fetch_assoc();
    $phone = $row["number"];
    $userName = $row["userName"];
    $standName = $row["standName"];
    if ($standName != NULL) {
        $bikeStatus = "B.{$bikeNum} " . _('is at') . " " . $standName . ".";
    } else {
        $bikeStatus = "B.{$bikeNum} " . _('is rented') . " by " . $userName . " (+" . $phone . ").";
    }
    $result = $db->query("SELECT userName from users where number={$number}");
    $row = $result->fetch_assoc();
    $reportedBy = $row["userName"];
    if (trim(strtoupper(preg_replace('/[0-9]+/', '', $message))) == "NOTE") {
        $userNote = "";
    } else {
        $matches = explode(" ", $message, 3);
        $userNote = $db->conn->real_escape_string(trim($matches[2]));
    }
    if ($userNote == "") {
        sendSMS($number, _('Empty note for bike') . " " . $bikeNum . " " . _('not saved, for deleting notes use DELNOTE (for admins)') . ".");
        /*checkUserPrivileges($number);
              sendSMS($number,_('Empty note for bike')." ".$bikeNum." "._('not saved, for deleting notes use DELNOTE.').".");
        
        	// @TODO remove SMS from deleting completely?
              $result=$db->query("UPDATE bikes SET note=NULL where bikeNum=$bikeNum");
              //only admins can delete and those will receive the confirmation in the next step.
              //sendSMS($number,"Note for bike $bikeNum deleted.");
              notifyAdmins(_('Note for bike')." ".$bikeNum." "._('deleted by')." ".$reportedBy.".");
              */
    } else {
        $db->query("INSERT INTO notes SET bikeNum='{$bikeNum}',userId='{$userId}',note='{$userNote}'");
        $noteid = $db->conn->insert_id;
        sendSMS($number, _('Note for bike') . " " . $bikeNum . " " . _('saved') . ".");
        notifyAdmins(_('Note #') . $noteid . ": b." . $bikeNum . " (" . $bikeStatus . ") " . _('by') . " " . $reportedBy . " (" . $number . "):" . $userNote);
    }
}
function addnote($userId, $bikeNum, $message)
{
    global $db;
    $userNote = $db->conn->real_escape_string(trim($message));
    $result = $db->query("SELECT userName,number from users where userId='{$userId}'");
    $row = $result->fetch_assoc();
    $userName = $row["userName"];
    $phone = $row["number"];
    $result = $db->query("SELECT stands.standName FROM bikes LEFT JOIN users on bikes.currentUser=users.userID LEFT JOIN stands on bikes.currentStand=stands.standId WHERE bikeNum={$bikeNum}");
    $row = $result->fetch_assoc();
    $standName = $row["standName"];
    if ($standName != NULL) {
        $bikeStatus = _('at') . " " . $standName;
    } else {
        $bikeStatus = _('used by') . " " . $userName . " +" . $phone;
    }
    $db->query("INSERT INTO notes SET bikeNum='{$bikeNum}',userId='{$userId}',note='{$userNote}'");
    $noteid = $db->conn->insert_id;
    notifyAdmins(_('Note #') . $noteid . ": b." . $bikeNum . " (" . $bikeStatus . ") " . _('by') . " " . $userName . "/" . $phone . ":" . $userNote);
}
function checktoomany($cron = 1, $userid = 0)
{
    global $db, $watches;
    $abusers = "";
    $found = 0;
    if ($cron) {
        $result = $db->query("SELECT users.userId,userName,userLimit FROM users LEFT JOIN limits ON users.userId=limits.userId");
        while ($row = $result->fetch_assoc()) {
            $userid = $row["userId"];
            $username = $row["userName"];
            $userlimit = $row["userLimit"];
            $currenttime = date("Y-m-d H:i:s", time() - $watches["timetoomany"] * 3600);
            $result2 = $db->query("SELECT bikeNum FROM history WHERE userId={$userid} AND action='RENT' AND time>'{$currenttime}'");
            if ($result2->num_rows >= $userlimit + $watches["numbertoomany"]) {
                $abusers .= " " . $result2->num_rows . " (" . _('limit') . " " . $userlimit . ") " . _('by') . " " . $username . ",";
                $found = 1;
            }
        }
    } else {
        $result = $db->query("SELECT users.userId,userName,userLimit FROM users LEFT JOIN limits ON users.userId=limits.userId WHERE users.userId={$userid}");
        $row = $result->fetch_assoc();
        $username = $row["userName"];
        $userlimit = $row["userLimit"];
        $currenttime = date("Y-m-d H:i:s", time() - $watches["timetoomany"] * 3600);
        $result = $db->query("SELECT bikeNum FROM history WHERE userId={$userid} AND action='RENT' AND time>'{$currenttime}'");
        if ($result->num_rows >= $userlimit + $watches["numbertoomany"]) {
            $abusers .= " " . $result->num_rows . " (" . _('limit') . " " . $userlimit . ") " . _('by') . " " . $username . ",";
            $found = 1;
        }
    }
    if ($found) {
        $abusers = substr($abusers, 0, strlen($abusers) - 1);
        notifyAdmins(_('Over limit in') . " " . $watches["timetoomany"] . " " . _('hs') . ":" . $abusers);
    }
}
function checktoomany($cron = 1, $userid = 0)
{
    global $watches;
    $abusers = "";
    $found = 0;
    if ($cron) {
        $rows = R::getAll('SELECT * FROM users LEFT JOIN limits ON users.id=limits.userid');
        $users = R::convertToBeans('users', $rows);
        if (!empty($users)) {
            foreach ($users as $user) {
                $numberofrentals = R::count('history', 'userid=:userid AND action=:action AND time>:time', [':userid' => $user->id, ':action' => 'RENT', 'time' => date("Y-m-d H:i:s", time() - $watches["timetoomany"] * 3600)]);
                if ($numberofrentals >= $userlimit + $watches["numbertoomany"]) {
                    $abusers .= " " . $numberofrentals . " (" . _('limit') . " " . $user->userlimit . ") " . _('by') . " " . $user->username . ",";
                    $found = 1;
                }
            }
        }
    } else {
        $rows = R::getAll('SELECT * FROM users LEFT JOIN limits ON users.id=limits.userid WHERE users.id=?', [$userid]);
        $users = R::convertToBeans('users', $rows);
        if (!empty($users)) {
            foreach ($users as $user) {
                $numberofrentals = R::count('history', 'userid=:userid AND action=:action AND time>:time', [':userid' => $user->id, ':action' => 'RENT', 'time' => date("Y-m-d H:i:s", time() - $watches["timetoomany"] * 3600)]);
                if ($result->num_rows >= $userlimit + $watches["numbertoomany"]) {
                    $abusers .= " " . $numberofrentals . " (" . _('limit') . " " . $user->userlimit . ") " . _('by') . " " . $user->username . ",";
                    $found = 1;
                }
            }
        }
    }
    if ($found) {
        $abusers = substr($abusers, 0, strlen($abusers) - 1);
        notifyAdmins(_('Over limit in') . " " . $watches["timetoomany"] . " " . _('hs') . ":" . $abusers);
    }
}