#include "ipfs/cid/cid.h"
#include "ipfs/path/path.h"

Resolver* ipfs_path_new_basic_resolver (DAGService *ds)
{
    Resolver *ret = malloc(sizeof(Resolver));
    if (!ret) return NULL;
    ret->DAG = ds;
    ret->ResolveOnce = ipfs_path_resolve_single;
    return ret;
}

// ipfs_path_split_abs_path clean up and split fpath. It extracts the first component (which
// must be a Multihash) and return it separately.
int ipfs_path_split_abs_path (struct Cid* cid, char ***parts, char *fpath)
{
    *parts = ipfs_path_split_segments(fpath);

    if (strcmp (**parts, "ipfs") == 0) *parts++;

    // if nothing, bail.
    if (!**parts) return ErrNoComponents;

    // first element in the path is a cid
    cid_decode_from_string(**parts, strlen(**parts), cid);
    return 0;
}

// ipfs_path_resolve_path fetches the node for given path. It returns the last item
// returned by ipfs_path_resolve_path_components.
int ipfs_path_resolve_path(Node **nd, Context ctx, Resolver *s, char *fpath)
{
    int err = IsValid(fpath);
    Node **ndd;

    if (err) {
        return err;
    }
    err = ipfs_path_resolve_path_components(&ndd, ctx, s, fpath);
    if (err) {
        return err;
    }
    if (ndd == NULL) {
        return ErrBadPath;
    }
    while(*ndd) {
        *nd = *ndd;
        ndd++;
    }
    return 0;
}

int ipfs_path_resolve_single(NodeLink **lnk, Context ctx, DAGService *ds, Node **nd, char *name)
{
    return ipfs_path_resolve_link(lnk, name);
}

// ipfs_path_resolve_path_components fetches the nodes for each segment of the given path.
// It uses the first path component as a hash (key) of the first node, then
// resolves all other components walking the links, with ipfs_path_resolve_links.
int ipfs_path_resolve_path_components(Node ***nd, Context ctx, Resolver *s, char *fpath)
{
    int err;
    struct Cid h;
    char **parts;

    err = ipfs_path_split_abs_path(&h, &parts, fpath);
    if (err) {
        return err;
    }

    //log.Debug("resolve dag get");
    //*nd = s->DAG.Get(ctx, h);
    //if (nd == DAG_ERR_VAL) {
    //   return DAG_ERR_VAL;
    //}

    return ipfs_path_resolve_links(ctx, *nd, parts);
}

// ipfs_path_resolve_links iteratively resolves names by walking the link hierarchy.
// Every node is fetched from the DAGService, resolving the next name.
// Returns the list of nodes forming the path, starting with ndd. This list is
// guaranteed never to be empty.
//
// ipfs_path_resolve_links(nd, []string{"foo", "bar", "baz"})
// would retrieve "baz" in ("bar" in ("foo" in nd.Links).Links).Links
int ipfs_path_resolve_links(Node ***result, Context ctx, Node *ndd, char **names)
{
    int err, idx = 0, l;
    NodeLink *lnk;
    Node *nd;

    *result = calloc (sizeof(Node*), ipfs_path_segments_length(names) + 1);
    if (!*result) {
        return -1;
    }
    memset (*result, NULL, sizeof(Node*) * (ipfs_path_segments_length(names)+1));

    *result[idx++] = ndd;
    nd = ndd; // dup arg workaround

    while (*names) {
        //TODO
        //var cancel context.CancelFunc
        //ctx, cancel = context.WithTimeout(ctx, time.Minute)
        //defer cancel()

        // for each of the path components
        err = ipfs_path_resolve_link(&lnk, *names);
        if (err) {
            char msg[51];
            *result[idx] = NULL;
            snprintf(msg, sizeof(msg), ErrPath[ErrNoLinkFmt], *names, nd->Cid);
            if (ErrPath[ErrNoLink]) {
                free(ErrPath[ErrNoLink]);
            }
            l = strlen(msg) + 1;
            ErrPath[ErrNoLink] = malloc(l);
            if (ErrPath[ErrNoLink]) {
                memcpy(ErrPath[ErrNoLink], msg, l);
            }
            free (*result);
            return ErrNoLink;
        }
        names++;
    }
    return 0;
}