f388fafa9a9b4c9436e4cc68a3eff0388fa7f388
tdreszer
  Wed Sep 22 13:37:42 2010 -0700
Changed slPair to hash in anticipation of PLANB being adopted.  Fixed bug in plan B
diff --git src/hg/lib/cart.c src/hg/lib/cart.c
index c857e49..7662879 100644
--- src/hg/lib/cart.c
+++ src/hg/lib/cart.c
@@ -2063,11 +2063,10 @@
 //#define COMPOSITE_VIS_SHAPING_PLAN_B
 
 #if defined(COMPOSITE_VIS_SHAPING_PLAN_A) || defined(COMPOSITE_VIS_SHAPING_PLAN_B)
-static int cartTdbParentShapeVis(struct cart *cart,struct trackDb *parent,char *view,struct slRef *refSubtracks,struct slPair *subVisVars,boolean compositeAtDefault)
+static int cartTdbParentShapeVis(struct cart *cart,struct trackDb *parent,char *view,struct slRef *refSubtracks,struct hash *subVisHash,boolean compositeAtDefault)
 // This shapes one level of vis (view or composite) based upon subtrack specific visibility.  Returns count of subtracks affected
 {
 int count=0;
-struct slPair *subVisVar = NULL;
 struct trackDb *subtrack = NULL;
 char setting[512];
 if (view != NULL)
@@ -2075,40 +2074,47 @@
 else
     safef(setting,sizeof(setting),"%s",parent->track);
 
-enum trackVisibility vis = tvHide;  // Looking for max vis of subtrack specific
+enum trackVisibility vis = tvHide;  // Looking for max vis of child subtracks
 enum trackVisibility visOrig = hTvFromString(cartUsualString(cart,setting,hStringFromTv(parent->visibility)));
-if (!compositeAtDefault)
-    vis = visOrig; // Default view vis to current vis
-for(subVisVar=subVisVars;subVisVar!=NULL;subVisVar=subVisVar->next)
-    {
-    if (endsWith(subVisVar->name,"_sel"))
+
+// Should walk through children and check for subtrackVis override
+struct slRef *refSub;
+for(refSub = refSubtracks;refSub != NULL;refSub = refSub->next)
         {
-        subtrack = subVisVar->val;
-        if (parent != subtrack->parent) // This should be true whether at view level or composite level,
-            continue;                   // since composite level call only happens composite has no views
+    subtrack = refSub->val;
+    if (parent != subtrack->parent) // This should work whether at view level or composite level,
+        continue;                   // since composite level call only happens if composite has no views
 
-        char *cartVis = cartOptionalString(cart,subtrack->track);
-        assert(cartVis != NULL); // Otherwise it wouldn't be in subVisVar
-        enum trackVisibility visSub = hTvFromString(cartVis);
+    char *foundVis = hashFindVal(subVisHash, subtrack->track); // if the subtrack doesn't have individual vis AND...
+    if (foundVis != NULL)
+        {
+        enum trackVisibility visSub = hTvFromString(foundVis);
+        if (tvCompare(vis, visSub) >= 0)
+            vis = visSub;
+        }
+    else
+        {
+        enum trackVisibility visSub = tdbVisLimitedByAncestry(NULL, subtrack, FALSE);
         if (tvCompare(vis, visSub) >= 0)
-            vis = visSub; // vis will wind up with setting of highest vis subtrack
+            vis = visSub;
         }
     }
+
+// Now we need to update non-subtrack specific vis/sel in cart
 if (vis != visOrig)
     {
+    //warn("%s vis old:%d new:%d",parent->track,visOrig,vis);
     cartSetString(cart,setting,hStringFromTv(vis));
 
     // Now set all subtracks that inherit vis back to visOrig
-    struct slRef *refSub;
     for(refSub = refSubtracks;refSub != NULL;refSub = refSub->next)
         {
         subtrack = refSub->val;
         if (parent != subtrack->parent) // This should work whether at view level or composite level,
             continue;                   // since composite level call only happens composite has no views
 
-        if (!slPairFind(subVisVars, subtrack->track))   // if the subtrack doesn't have individual vis AND...
+        if (!hashFindVal(subVisHash, subtrack->track))   // if the subtrack doesn't have individual vis AND...
             {
-            // FIXME problem is fourState gets cached
             int fourState = subtrackFourStateChecked(subtrack,cart);
             if (fourStateChecked(fourState))            // subtrack is checked
                 {
@@ -2127,21 +2133,45 @@
 return count;
 }
 
-static boolean cartVarsAllFoundForTdb(struct cart *cart,struct slPair *subVisVars,struct trackDb *tdb)
+static boolean cartVarsNoneFoundForTdb(struct cart *cart,struct hash *subVisHash,struct trackDb *tdb)
 {
 struct slPair *cartVar,*cartVars = cartVarsWithPrefix(cart,tdb->track);
 if (cartVars != NULL)
     {
     for (cartVar = cartVars; cartVar != NULL; cartVar = cartVar->next)
         {
-        if (tdbIsCompositeView(tdb) || !slPairFind(subVisVars, cartVar->name)) // subVisVars does not contain anything prefixed by view!
+        if (tdbIsCompositeView(tdb) || !hashFindVal(subVisHash, cartVar->name)) // subVisHash does not contain anything prefixed by view!
             {
-            // NOTE: This is less than ideal!  Composites (not memebers of superTracks) are getting their cart vis set on hgTracks:config page!
+            // If composite vis changed but it is the same as trackDb default then ignore it
             if (tdbIsComposite(tdb)
             &&  sameString(cartVar->name,tdb->track)
             &&  sameString((char *)cartVar->val,hStringFromTv(tdb->visibility)) )
                 continue;
 
+            // If view vis changed but it is the same as trackDb default then ignore it
+            if (tdbIsComposite(tdb)
+            && endsWith((char *)cartVar->val,".vis"))
+                {
+                // find out view
+                char *val = skipBeyondDelimit(cartVar->name,'.');
+                char *viewFound = cloneFirstWordByDelimiter(val,'.');
+                if (viewFound)
+                    {
+                    // find tdb for View
+                    struct trackDb *viewTdb;
+                    for (viewTdb=tdb->subtracks; viewTdb!=NULL; viewTdb=viewTdb->next)
+                        {
+                        char *viewOfTdb = trackDbLocalSetting(viewTdb,"view");
+                        if (viewOfTdb && sameString(viewOfTdb,viewFound))
+                            {
+                            if(sameString((char *)cartVar->val,hStringFromTv(viewTdb->visibility)) )
+                                continue;
+                            break;
+                            }
+                        }
+                    }
+                }
+            //warn("cartVarsNoneFoundForTdb: %s=%s",cartVar->name,(char *)cartVar->val);
             slFreeList(&cartVars);
             return FALSE; // Any view cart vars means non-default so do not "shape" composite
             }
@@ -2160,10 +2190,10 @@
     return FALSE;  // Don't do any shaping
 #else/// if defined(COMPOSITE_VIS_SHAPING_PLAN_A) || defined(COMPOSITE_VIS_SHAPING_PLAN_B)
 
-// First look for subtrack vis
+// First look for subtrack level vis
 char setting[512];
 struct trackDb *subtrack = NULL;
-struct slPair *subVisVar, *subVisVars = NULL;
+struct hash *subVisHash = newHash(8);
 struct slRef *tdbRef, *tdbRefList = trackDbListGetRefsToDescendantLeaves(tdbComposite->subtracks);
 for (tdbRef = tdbRefList; tdbRef != NULL; tdbRef = tdbRef->next)
     {
@@ -2171,15 +2201,13 @@
     char *val=cartOptionalString(cart,subtrack->track);
     if (val && differentString(val,"hide"))  // NOTE should we include hide?
         {
-        subVisVar = slPairNew(subtrack->track,val); // subtrack has sub level vis
-        slAddHead(&subVisVars,subVisVar);
+        hashAdd(subVisHash,subtrack->track,val);
         // Add the "_sel" setting which should also exist.  Point it to subtrack
         safef(setting,sizeof(setting),"%s_sel",subtrack->track);
-        subVisVar = slPairNew(setting,subtrack);
-        slAddHead(&subVisVars,subVisVar);
+        hashAdd(subVisHash,setting,subtrack);
         }
     }
-if (slCount(subVisVars) == 0)
+if (hashNumEntries(subVisHash) == 0)
     {
     slFreeList(&tdbRefList);
     return FALSE;
@@ -2187,37 +2215,25 @@
 
 // Next look for any cart settings other than subtrack vis/sel
 boolean compositeAtDefault = TRUE;
-compositeAtDefault = cartVarsAllFoundForTdb(cart,subVisVars,tdbComposite);
-#ifndef COMPOSITE_VIS_SHAPING_PLAN_B
-if (!compositeAtDefault)
-    {
-    slFreeList(&tdbRefList);
-    slFreeList(&subVisVars);
-    return FALSE; // Any view cart vars means non-default so do not "shape" composite
-    }
-#endif///ndef COMPOSITE_VIS_SHAPING_PLAN_B
+compositeAtDefault = cartVarsNoneFoundForTdb(cart,subVisHash,tdbComposite);
 
 // What about view level settings?
 struct trackDb *tdbView = tdbComposite->subtracks;
 boolean hasViews = FALSE;
 if (tdbIsCompositeView(tdbView))
     {
+    hasViews = TRUE;
     if (compositeAtDefault)
         {
         for( ;tdbView != NULL; tdbView = tdbView->next )
             {
-            compositeAtDefault = cartVarsAllFoundForTdb(cart,subVisVars,tdbView);
-            #ifndef COMPOSITE_VIS_SHAPING_PLAN_B
-            if (!compositeAtDefault)
+            if(!cartVarsNoneFoundForTdb(cart,subVisHash,tdbView))
                 {
-                slFreeList(&tdbRefList);
-                slFreeList(&subVisVars);
-                return FALSE; // Any view cart vars means non-default so do not "shape" composite
+                compositeAtDefault = FALSE;
+                break;
                 }
-            #endif///ndef COMPOSITE_VIS_SHAPING_PLAN_B
             }
         }
-    hasViews = TRUE;
     }
 
 // How about subtrack level settings?  Assume that compositePrefix caught them? If views then YES
@@ -2225,17 +2241,22 @@
     {
     for(tdbRef = tdbRefList;tdbRef != NULL; tdbRef = tdbRef->next )
         {
-        compositeAtDefault = cartVarsAllFoundForTdb(cart,subVisVars,subtrack);
+        if (!cartVarsNoneFoundForTdb(cart,subVisHash,subtrack));
+            {
+            compositeAtDefault = FALSE;
+            break;
+            }
+        }
+    }
+//warn("compositeAtDefault:%s",compositeAtDefault?"TRUE":"FALSE");
         #ifndef COMPOSITE_VIS_SHAPING_PLAN_B
         if (!compositeAtDefault)
             {
             slFreeList(&tdbRefList);
-            slFreeList(&subVisVars);
+    hashFree(&subVisHash);
             return FALSE; // Any view cart vars means non-default so do not "shape" composite
             }
         #endif///ndef COMPOSITE_VIS_SHAPING_PLAN_B
-        }
-    }
 
 // Now shape views and composite to match subtrack specific visibility
     int count = 0;
@@ -2245,14 +2266,14 @@
         {
         char *view = trackDbSetting(tdbView,"view");
         assert(view != NULL);
-        count += cartTdbParentShapeVis(cart,tdbView,view,tdbRefList,subVisVars,compositeAtDefault);
+        count += cartTdbParentShapeVis(cart,tdbView,view,tdbRefList,subVisHash,compositeAtDefault);
         }
     }
 else // If no views then composite is not set to fuul but to max of subtracks
-    count = cartTdbParentShapeVis(cart,tdbComposite,NULL,tdbRefList,subVisVars,compositeAtDefault);
+    count = cartTdbParentShapeVis(cart,tdbComposite,NULL,tdbRefList,subVisHash,compositeAtDefault);
 
 slFreeList(&tdbRefList);
-slFreeList(&subVisVars);
+hashFree(&subVisHash);
 return TRUE;
 #endif/// defined(COMPOSITE_VIS_SHAPING_PLAN_A) || defined(COMPOSITE_VIS_SHAPING_PLAN_B)
 }