/* A more-or-less generic container class that hopefully will someday encompass
 * the superTrack and subTrack systems.  Tracks that have the tag "container"
 * get sent here for processing. */

/* Copyright (C) 2013 The Regents of the University of California 
 * See kent/LICENSE or http://genome.ucsc.edu/license/ for licensing information. */

#include "common.h"
#include "hash.h"
#include "linefile.h"
#include "jksql.h"
#include "hdb.h"
#include "hgTracks.h"
#include "container.h"


void containerLoadItems(struct track *track)
/* containerLoadItems - call load routine on all children. */
{
struct track *subtrack;
for (subtrack = track->subtracks; subtrack != NULL; subtrack = subtrack->next)
    {
    if (isSubtrackVisible(subtrack) && !subtrack->parallelLoading)
	subtrack->loadItems(subtrack);
    }
}

static void containerFree(struct track *track)
/* containerFree - call free routine on all children. */
{
struct track *subtrack;
for (subtrack = track->subtracks; subtrack != NULL; subtrack = subtrack->next)
    subtrack->freeItems(subtrack);
}

void containerDrawItems(struct track *track, int seqStart, int seqEnd,
        struct hvGfx *hvg, int xOff, int yOff, int width, 
        MgFont *font, Color color, enum trackVisibility vis)
/* Draw items in container. */
{
struct track *subtrack;
int y = yOff;
for (subtrack = track->subtracks; subtrack != NULL; subtrack = subtrack->next)
    {
    if (isSubtrackVisible(subtrack))
	{
	subtrack->drawItems(subtrack, seqStart, seqEnd, hvg, xOff, y, width, font, color, 
		vis);
	y += subtrack->totalHeight(subtrack, subtrack->limitedVis);
	}
    }
}

static int containerTotalHeight(struct track *track, enum trackVisibility vis)
/* Return total height of container. */
{
int totalHeight = 0;
struct track *subtrack;
for (subtrack = track->subtracks; subtrack != NULL; subtrack = subtrack->next)
    {
    if (isSubtrackVisible(subtrack))
	{
	totalHeight += subtrack->totalHeight(subtrack, vis);
	track->lineHeight = subtrack->lineHeight;
	track->heightPer = subtrack->heightPer;
	}
    }
track->height = totalHeight;
return totalHeight;
}

char *parentContainerType(struct track *track)
/* Determine parent's container type if any or NULL */
{
if (track->parent && track->parent->tdb)
    return trackDbSetting(track->parent->tdb, "container");
else
    return NULL;
}

void makeContainerTrack(struct track *track, struct trackDb *tdb)
/* Construct track subtrack list from trackDb entry for container tracks. */
{
/* Wrap tracks around child tdb's, maintaining same heirarchy as in tdb. */
struct trackDb *subtdb;
for (subtdb = tdb->subtracks; subtdb != NULL; subtdb = subtdb->next)
    {
    struct track *subtrack = trackFromTrackDb(subtdb);
    TrackHandler handler = lookupTrackHandlerClosestToHome(subtdb);
    if (handler != NULL)
	handler(subtrack);
    slAddHead(&track->subtracks, subtrack);
    subtrack->parent = track;
    if (subtdb->subtracks != NULL)
	makeContainerTrack(subtrack, subtdb);
    }
slSort(&track->subtracks, trackPriCmp);

/* Set methods that may be shared by all containers. */
track->loadItems = containerLoadItems;
track->freeItems = containerFree;
track->drawItems = containerDrawItems;
track->totalHeight = containerTotalHeight;

/* Set methods specific to containers. */
char *containerType = trackDbSetting(tdb, "container");
if (sameString(containerType, "multiWig"))
    {
    multiWigContainerMethods(track);
    }
else
    errAbort("unknown container type %s in trackDb for %s", containerType, tdb->track);
}


