github.com/pbberlin/tools@v0.0.0-20160910141205-7aa5421c2169/appengine/backend/backend3.go (about)

     1  package backend
     2  
     3  import (
     4  	sc "github.com/pbberlin/tools/dsu/distributed_unancestored"
     5  	"github.com/pbberlin/tools/net/http/htmlfrag"
     6  	"github.com/pbberlin/tools/net/http/loghttp"
     7  	"github.com/pbberlin/tools/net/http/tplx"
     8  	"google.golang.org/appengine"
     9  
    10  	// "github.com/davecgh/go-spew/spew"
    11  	"net/http"
    12  	"sort"
    13  	"strings"
    14  
    15  	"github.com/pbberlin/tools/util"
    16  	aelog "google.golang.org/appengine/log"
    17  )
    18  
    19  /*
    20  	I would love to use slices of *interfaces*,
    21  	instead of fixed types
    22  
    23  	VB1        []interface{}   <---- preferable
    24  	VB1        []b1            <---- restrictive
    25  
    26  	But it is complicated to reach
    27  	the pointers to the actual structs,
    28  	if the structs are wrapped behind an interface.
    29  
    30  		myB1 := &(myB0.VB1a[i1])
    31  		myB1.Fieldname += "_BBBBB" // works
    32  
    33  		myB1, ok := myB0.VB1[i1].(b1)
    34  		if !ok ...
    35  		myB1.Fieldname += "_BBBBB" // not working
    36  
    37  		myB1 := &(myB0.VB1[i1].(b1))   // impossible - "cannot take the address ..."
    38  		myB1 := &(myB0.VB1[i1]).(*b1)  // impossible
    39  
    40  		(myB0.VB1[i1].(b1)).Heading += "_AAAAA" // impossible - "can not assign ..."
    41  
    42  
    43  	This solution seems not applicable without writing accessor methods for each field:
    44  	https://groups.google.com/forum/#!topic/golang-nuts/bxbUdSYdTSI
    45  
    46  
    47  	These are possible solutions, both using reflection
    48  	http://stackoverflow.com/questions/6395076/in-golang-using-reflect-how-do-you-set-the-value-of-a-struct-field
    49  	http://stackoverflow.com/questions/21379466/golang-get-a-pointer-to-a-field-of-a-struct-trough-an-interface
    50  
    51  	I implemented the first solution in util.GetIntField(),
    52  	but it's not working with generic arguments.
    53  
    54  	The second solution is too much complication for me -
    55  	 I fall back to explicit typing:
    56  
    57  	for i1, _ := range myB0.VB1 {
    58  
    59  		myB0.VB1a[i1].Heading += "_AAAAA" // works
    60  
    61  		myB1 := &(myB0.VB1a[i1])
    62  		myB1.Heading += "_BBBBB" // works
    63  
    64  		myB2 := (&myB0).VB1a[i1]
    65  		myB2.Heading += "_CCCCC" // works NOT
    66  
    67  		myB3 := myB0.VB1a[i1]
    68  		myB3.Heading += "_DDDDD" // works NOT
    69  
    70  	}
    71  
    72  */
    73  
    74  //var myB0 = b0{NumYSectors: 2}
    75  var myB0 B0 = B0{NumYSectors: 2}
    76  
    77  func backend3(w http.ResponseWriter, r *http.Request, m map[string]interface{}) {
    78  
    79  	c := appengine.NewContext(r)
    80  
    81  	var nColsBlock = 4
    82  	if r.FormValue("nColsBlock") != "" {
    83  		nColsBlock = util.Stoi(r.FormValue("nColsBlock"))
    84  	}
    85  	var nColsViewport = 6
    86  	if r.FormValue("nColsViewport") != "" {
    87  		nColsViewport = util.Stoi(r.FormValue("nColsViewport"))
    88  	}
    89  
    90  	myB0.VB1 = X
    91  	myB0.NumB1 = len(myB0.VB1)
    92  	myB0.NumB2 = 0
    93  	myB0.NColsViewport = nColsViewport
    94  
    95  	// compute basic meta data
    96  	for i1, _ := range myB0.VB1 {
    97  		myB0.NumB2 += len(myB0.VB1[i1].VB2)
    98  		for i2, _ := range myB0.VB1[i1].VB2 {
    99  			// number of chars
   100  			ro := myB0.VB1[i1].VB2[i2] // read only
   101  			myB0.VB1[i1].VB2[i2].Size = len(ro.Linktext) + len(ro.Description)
   102  			myB0.VB1[i1].VB2[i2].EditorialIndex = i2
   103  		}
   104  	}
   105  
   106  	// compute NCols - NRows for the block
   107  	for i1, _ := range myB0.VB1 {
   108  		myB0.VB1[i1].NCols = nColsBlock
   109  		if myB0.VB1[i1].NColsEditorial > 0 {
   110  			myB0.VB1[i1].NCols = myB0.VB1[i1].NColsEditorial
   111  		}
   112  		if len(myB0.VB1[i1].VB2) < nColsBlock && len(myB0.VB1[i1].VB2) > 0 {
   113  			myB0.VB1[i1].NCols = len(myB0.VB1[i1].VB2)
   114  		}
   115  		myB0.VB1[i1].NRows = complementRowsOrCols(len(myB0.VB1[i1].VB2), myB0.VB1[i1].NCols)
   116  		myB0.VB1[i1].Discrepancy = myB0.VB1[i1].NCols*myB0.VB1[i1].NRows - len(myB0.VB1[i1].VB2)
   117  
   118  		myB0.MaxNCols = util.Max(myB0.MaxNCols, myB0.VB1[i1].NCols)
   119  		myB0.MaxNRows = util.Max(myB0.MaxNRows, myB0.VB1[i1].NRows)
   120  	}
   121  
   122  	// compute NCols - NRows - sizeup to MaxNRows
   123  	for i1, _ := range myB0.VB1 {
   124  		if myB0.VB1[i1].NRows < myB0.MaxNRows {
   125  			myB0.VB1[i1].NRows = myB0.MaxNRows
   126  			myB0.VB1[i1].NCols = complementRowsOrCols(len(myB0.VB1[i1].VB2), myB0.VB1[i1].NRows)
   127  			myB0.VB1[i1].Discrepancy = myB0.VB1[i1].NCols*myB0.VB1[i1].NRows - len(myB0.VB1[i1].VB2)
   128  		}
   129  	}
   130  
   131  	// is first or last
   132  	for i1, _ := range myB0.VB1 {
   133  		for i2, _ := range myB0.VB1[i1].VB2 {
   134  			myB0.VB1[i1].VB2[i2].IsFirst = false
   135  			myB0.VB1[i1].VB2[i2].IsLast = false
   136  			if i2%myB0.VB1[i1].NCols == 0 {
   137  				myB0.VB1[i1].VB2[i2].IsFirst = true
   138  			}
   139  			if i2%myB0.VB1[i1].NCols == (myB0.VB1[i1].NCols - 1) {
   140  				myB0.VB1[i1].VB2[i2].IsLast = true
   141  			}
   142  			//aelog.Infof(c,"first-last %v %v \n", i2, i2%myB0.VB1[i1].NCols)
   143  		}
   144  	}
   145  
   146  	// create slices with the data to be sorted
   147  	for i1, _ := range myB0.VB1 {
   148  		sh1 := make([]Order, len(myB0.VB1[i1].VB2))
   149  		myB0.VB1[i1].BySize = ByInt(sh1)
   150  		sh2 := make([]Order, len(myB0.VB1[i1].VB2))
   151  		myB0.VB1[i1].ByHeading = ByStr(sh2)
   152  		// fill in the data - to be sorted later
   153  		for i2, _ := range myB0.VB1[i1].VB2 {
   154  			ro := myB0.VB1[i1].VB2[i2] // read only
   155  			myB0.VB1[i1].BySize[i2].IdxSrc = i2
   156  			myB0.VB1[i1].BySize[i2].ByI = len(ro.Linktext) + len(ro.Description)
   157  			myB0.VB1[i1].ByHeading[i2].IdxSrc = i2
   158  			myB0.VB1[i1].ByHeading[i2].ByS = strings.ToLower(ro.Linktext)
   159  		}
   160  	}
   161  
   162  	// actual rearranging of the sorting date
   163  	for i1, _ := range myB0.VB1 {
   164  		sort.Sort(myB0.VB1[i1].BySize)
   165  		sort.Sort(myB0.VB1[i1].ByHeading)
   166  		aelog.Infof(c, "-- Sorting %v", myB0.VB1[i1].Heading)
   167  		// for i, v := range myB0.VB1[i1].BySize {
   168  		// 	aelog.Infof(c,"---- %v %v %v", i, v.IdxSrc, v.ByI)
   169  		// }
   170  		// for i, v := range myB0.VB1[i1].ByHeading {
   171  		// 	aelog.Infof(c,"---- %v %v %v", i, v.IdxSrc, v.ByS)
   172  		// }
   173  	}
   174  
   175  	path := m["dir"].(string) + m["base"].(string)
   176  
   177  	cntr, _ := sc.Count(c, path)
   178  
   179  	add, tplExec := tplx.FuncTplBuilder(w, r)
   180  	add("n_html_title", "Backend", nil)
   181  
   182  	add("n_cont_0", "<style>"+htmlfrag.CSSColumnsWidth(nColsViewport)+"</style>", "")
   183  	add("n_cont_1", tplx.PrefixLff+"backend3_body", myB0)
   184  	add("tpl_legend", tplx.PrefixLff+"backend3_body_embed01", "")
   185  	add("n_cont_2", "<p>{{.}} views</p>", cntr)
   186  
   187  	sDumped := ""
   188  	//sDumped = spew.Sdump(myB0)
   189  	add("n_cont_3", "<pre>{{.}} </pre>", sDumped)
   190  
   191  	tplExec(w, r)
   192  
   193  }
   194  
   195  func prepareLayout(l B0) {
   196  
   197  }
   198  
   199  func complementRowsOrCols(nBlocks int, nRowOrCol int) int {
   200  	if nRowOrCol < 1 {
   201  		panic("Count of Cols or Rows must be given")
   202  	}
   203  	nCompl := nBlocks / nRowOrCol
   204  	if nBlocks%nRowOrCol != 0 {
   205  		nCompl++
   206  	}
   207  	return nCompl
   208  
   209  }
   210  
   211  func init() {
   212  	prepareLayout(myB0)
   213  	http.HandleFunc("/backend3", loghttp.Adapter(backend3))
   214  }