/* ----------------------------------------------
*/
#include "afpcmd.h"
#include "afphelper.h"
#include "testhelper.h"

/* ------------------------- */
STATIC void test69()
{
    int  dir;
    char *name = "t69 rename file!name";
    char *name2 = "t69 new name";
    uint16_t vol = VolID;
    ENTER_TEST

    if (!(dir = FPCreateDir(Conn, vol, DIRDID_ROOT, name))) {
        test_nottested();
        goto test_exit;
    }

    FAIL(FPRename(Conn, vol, DIRDID_ROOT, name, name2))
    FAIL(!(dir = FPCreateDir(Conn, vol, DIRDID_ROOT, name)))
    FAIL(FPDelete(Conn, vol, DIRDID_ROOT, name2))
    FAIL(!(dir = FPCreateDir(Conn, vol, DIRDID_ROOT, name2)))
    FAIL(htonl(AFPERR_EXIST) != FPRename(Conn, vol, DIRDID_ROOT, name, name2))
    FAIL(FPDelete(Conn, vol, DIRDID_ROOT, name2))
    FAIL(FPRename(Conn, vol, DIRDID_ROOT, name, name2))
    FAIL(FPDelete(Conn, vol, DIRDID_ROOT, name2))
    /* other sens */
    FAIL(!(dir = FPCreateDir(Conn, vol, DIRDID_ROOT, name2)))
    FAIL(FPRename(Conn, vol, DIRDID_ROOT, name2, name))
    FAIL(FPDelete(Conn, vol, DIRDID_ROOT, name))
test_exit:
    exit_test("FPRename:test69: rename a folder with Unix name != Mac name");
}

/* ------------------------- */
STATIC void test72()
{
    int dir = 0;
    int dir1 = 0;
    uint16_t bitmap = 0;
    char *name  = "t72 check rename input";
    char *ndel = "t72 no delete dir";
    char *name1 = "t72 new folder";
    char *name2 = "t72 dir";
    unsigned int ret;
    int  ofs =  3 * sizeof(uint16_t);
    struct afp_filedir_parms filedir;
    uint16_t vol = VolID;
    const DSI *dsi = &Conn->dsi;
    ENTER_TEST

    if (!(dir = FPCreateDir(Conn, vol, DIRDID_ROOT, name2))) {
        test_nottested();
        goto test_exit;
    }

    if (!(dir1 = FPCreateDir(Conn, vol, DIRDID_ROOT, ndel))) {
        test_nottested();
        goto fin;
    }

    FAIL(ntohl(AFPERR_NORENAME) != FPRename(Conn, vol, DIRDID_ROOT, "", "volume"))
    bitmap = (1 << DIRPBIT_ATTR);

    if (FPGetFileDirParams(Conn, vol, dir1, "", 0, bitmap)) {
        test_failed();
    } else {
        filedir.isdir = 1;
        afp_filedir_unpack(&filedir, dsi->data + ofs, 0, bitmap);
        filedir.attr = ATTRBIT_NORENAME | ATTRBIT_SETCLR ;
        FAIL(FPSetDirParms(Conn, vol, dir1, "", bitmap, &filedir))
        ret = FPRename(Conn, vol, DIRDID_ROOT, ndel, "volume");

        if (ntohl(AFPERR_OLOCK) != ret) {
            test_failed();

            if (!ret) {
                FPRename(Conn, vol, DIRDID_ROOT, "volume", ndel);
            }
        }

        filedir.attr = ATTRBIT_NODELETE;
        FAIL(FPSetDirParms(Conn, vol, dir1, "", bitmap, &filedir))
    }

    ret = FPRename(Conn, vol, DIRDID_ROOT, name2, name2);

    if (not_valid(ret, /* MAC */0, AFPERR_EXIST)) {
        test_failed();
    }

    FAIL(FPCreateFile(Conn, vol, 0, DIRDID_ROOT, name))
    FAIL(FPRename(Conn, vol, DIRDID_ROOT, name, name))
    FAIL(FPRename(Conn, vol, DIRDID_ROOT, name, name1))
    FAIL(ntohl(AFPERR_NOOBJ) != FPDelete(Conn, vol, DIRDID_ROOT, name))
fin:
    FAIL(FPDelete(Conn, vol, DIRDID_ROOT, ndel))
    FAIL(FPDelete(Conn, vol, DIRDID_ROOT, name1))
    FAIL(FPDelete(Conn, vol, DIRDID_ROOT, name2))
test_exit:
    exit_test("FPRename:test72: check input parameter");
}

/* -------------------------- */
static int create_double_deleted_folder(uint16_t vol, char *name)
{
    uint16_t vol2;
    int tdir;
    int tdir1 = 0;
    int  ofs =  3 * sizeof(uint16_t);
    struct afp_filedir_parms filedir;
    const DSI *dsi = &Conn->dsi;
    const DSI *dsi2;
    uint16_t bitmap;
    int tp, tp1;
    tdir  = FPCreateDir(Conn, vol, DIRDID_ROOT, name);

    if (!tdir) {
        test_nottested();
        return 0;
    }

    tdir1  = FPCreateDir(Conn, vol, tdir, name);

    if (!tdir1) {
        test_nottested();
        goto fin;
    }

    if (FPGetFileDirParams(Conn, vol, tdir1, "", 0, (1 << DIRPBIT_OFFCNT))) {
        test_nottested();
        goto fin;
    }

    bitmap = (1 << DIRPBIT_ACCESS);

    if (FPGetFileDirParams(Conn, vol, tdir, "", 0, bitmap)) {
        test_nottested();
        goto fin;
    }

    filedir.isdir = 1;
    afp_filedir_unpack(&filedir, dsi->data + ofs, 0, bitmap);
    filedir.access[0] = 0;
    filedir.access[1] = 7;
    filedir.access[2] = 7;
    filedir.access[3] = 7;

    if (FPSetDirParms(Conn, vol, tdir, "", bitmap, &filedir)) {
        test_nottested();
        goto fin;
    }

    dsi2 = &Conn2->dsi;
    vol2  = FPOpenVol(Conn2, Vol);

    if (vol2 == 0xffff) {
        test_nottested();
        goto fin;
    }

    bitmap = (1 << DIRPBIT_ACCESS) | (1 << DIRPBIT_PDID) | (1 << DIRPBIT_DID);

    if (FPGetFileDirParams(Conn2, vol2,  DIRDID_ROOT, name, 0, bitmap)) {
        test_nottested();
        goto fin;
    }

    tp = get_did(Conn2, vol2, DIRDID_ROOT, name);

    if (!tp) {
        test_nottested();
        goto fin;
    }

    if (tp != tdir && !Quiet) {
        fprintf(stdout, "Warning DID connection1 0x%x ==> connection2 0x%x\n", tdir,
                tp);
    }

    tp1 = get_did(Conn2, vol2, tp, name);

    if (!tp1) {
        test_nottested();
        goto fin;
    }

    if (tp1 != tdir1 && !Quiet) {
        fprintf(stdout, "Warning DID connection1 0x%x ==> connection2 0x%x\n", tdir1,
                tp1);
    }

    if (FPDelete(Conn2, vol2,  tp1, "")) {
        test_nottested();
        FPDelete(Conn, vol, tdir1, "");
        tdir1 = 0;
    }

    if (FPDelete(Conn2, vol2,  tp, "")) {
        test_nottested();
        FPDelete(Conn, vol, tdir, "");
        tdir1 = 0;
    }

    FPCloseVol(Conn2, vol2);
    return tdir1;
fin:
    FAIL(tdir && FPDelete(Conn, vol, tdir, ""))
    FAIL(tdir1 && FPDelete(Conn, vol, tdir1, ""))
    return 0;
}

/* ----------- */
STATIC void test183()
{
    char *tname = "test183";
    char *name1 = "test183.new";
    int tdir;
    uint16_t vol = VolID;
    ENTER_TEST

    if (!Conn2) {
        test_skipped(T_CONN2);
        goto test_exit;
    }

    /* ---- directory.c ---- */
    if (!(tdir = create_double_deleted_folder(vol, tname))) {
        goto test_exit;
    }

    FAIL(ntohl(AFPERR_NOOBJ) != FPDelete(Conn, vol, tdir, ""))

    /* ---- filedir.c ------------ */
    if (!(tdir = create_double_deleted_folder(vol, tname))) {
        goto test_exit;
    }

    FAIL(ntohl(AFPERR_NOOBJ) != FPRename(Conn, vol, tdir, "", name1))
test_exit:
    exit_test("FPRename:test183: did error two users in  folder did=<deleted> name=test183");
}

/* ------------------------- */
STATIC void test184()
{
    char *name  = "t184.txt";
    char *name1 = "t184new.txt";
    uint16_t vol = VolID;
    ENTER_TEST

    if (FPCreateFile(Conn, vol, 0, DIRDID_ROOT, name)) {
        test_nottested();
        goto test_exit;
    }

    FAIL(FPRename(Conn, vol, DIRDID_ROOT, name, name1))
    FAIL(FPDelete(Conn, vol, DIRDID_ROOT, name1))
    FAIL(!FPDelete(Conn, vol, DIRDID_ROOT, name))
    FPFlush(Conn, vol);
test_exit:
    exit_test("FPRename:test184: rename");
}

/* ------------------------- */
STATIC void test191()
{
    char *name = "t191 dir";
    char *name1 = "t191 subdir";
    char *dest = "t191 newname";
    uint16_t vol = VolID;
    int  dir = 0, dir1 = 0, dir2 = 0;
    ENTER_TEST
    dir  = FPCreateDir(Conn, vol, DIRDID_ROOT, name);

    if (!dir) {
        test_nottested();
        goto test_exit;
    }

    dir1  = FPCreateDir(Conn, vol, DIRDID_ROOT, name1);

    if (!dir1) {
        test_nottested();
        goto fin;
    }

    dir2  = FPCreateDir(Conn, vol, dir1, name1);

    if (!dir2) {
        test_nottested();
        goto fin;
    }

    if (FPRename(Conn, vol, DIRDID_ROOT, name, dest)) {
        test_failed();
    }

fin:
    FAIL(dir2 && FPDelete(Conn, vol, dir2, ""))
    FAIL(dir1 && FPDelete(Conn, vol, dir1, ""))
    FAIL(dir && FPDelete(Conn, vol, dir, ""))
test_exit:
    exit_test("FPRename:test191: rename folders");
}

/* ------------------------- */
STATIC void test219()
{
    char *name = "t191 dir";
    char *dest = "t191 newname";
    uint16_t vol = VolID;
    uint16_t vol2, bitmap;
    int  dir = 0;
    DSI	*dsi2 = &Conn2->dsi;
    ENTER_TEST

    if (!Conn2) {
        test_skipped(T_CONN2);
        goto test_exit;
    }

    dir  = FPCreateDir(Conn, vol, DIRDID_ROOT, name);

    if (!dir) {
        test_nottested();
        goto test_exit;
    }

    dsi2 = &Conn2->dsi;
    vol2  = FPOpenVol(Conn2, Vol);

    if (vol2 == 0xffff) {
        test_nottested();
        goto fin;
    }

    /* FIXME: FPEnumerate* uses my_dsi_data_receive. See afphelper.c:delete_directory_tree() */
    bitmap = (1 << FILPBIT_LNAME);
    FAIL(FPEnumerate(Conn, vol, DIRDID_ROOT, "", bitmap, bitmap))
    FAIL(FPEnumerate(Conn2, vol2,  DIRDID_ROOT, "", bitmap, bitmap))

    if (FPRename(Conn2, vol2, DIRDID_ROOT, name, dest)) {
        test_failed();
    }

    FAIL(FPEnumerate(Conn, vol, DIRDID_ROOT, "", bitmap, bitmap))
    FAIL(FPCloseVol(Conn2, vol2))
fin:
    FAIL(dir && FPDelete(Conn, vol, dir, ""))
test_exit:
    exit_test("FPRename:test219: rename folders two users");
}

/* ------------------------- */
STATIC void test376()
{
    char *name = "t376 name";
    char *name1 = "t376 new name";
    uint16_t vol = VolID;
    ENTER_TEST

    if (FPCreateFile(Conn, vol, 0, DIRDID_ROOT, name)) {
        test_failed();
        goto test_exit;
    }

    if (FPCreateFile(Conn, vol, 0, DIRDID_ROOT, name1)) {
        test_failed();
        goto fin;
    }

    FAIL(htonl(AFPERR_EXIST) != FPRename(Conn, vol, DIRDID_ROOT, name, name1))
    FAIL(FPDelete(Conn, vol, DIRDID_ROOT, name1))
fin:
    FPDelete(Conn, vol, DIRDID_ROOT, name);
test_exit:
    exit_test("FPRename:test376: dest file exist");
}


/* -------------------------
*/
STATIC void test377()
{
    char *name =  "t377 name";
    char *name1 = "t377 Name";
    uint16_t vol = VolID;
    int ret;
    ENTER_TEST

    if (FPCreateFile(Conn, vol, 0, DIRDID_ROOT, name)) {
        test_failed();
        goto test_exit;
    }

    if ((ret = FPCreateFile(Conn, vol, 0, DIRDID_ROOT, name1))
            && ret != htonl(AFPERR_EXIST)) {
        test_failed();
        goto fin;
    }

    if (ret == htonl(AFPERR_EXIST)) {
        FAIL(FPRename(Conn, vol, DIRDID_ROOT, name, name1))
    } else {
        FAIL(htonl(AFPERR_EXIST) != FPRename(Conn, vol, DIRDID_ROOT, name, name1))
    }

    FAIL(FPDelete(Conn, vol, DIRDID_ROOT, name1))
fin:
    FPDelete(Conn, vol, DIRDID_ROOT, name);
test_exit:
    exit_test("FPRename:test377: dest file exist but diff only by case, is this one OK");
}


/* ----------- */
void FPRename_test()
{
    ENTER_TESTSET
    test69();
    test72();
    test183();
    test184();
    test191();
    test219();
    test376();
    test377();
}
