Support new SADIS configuration to support multi-tcont

Change-Id: I4cf0d7495832a5883e4f75ba60d88e6bb0f79f1e
diff --git a/VERSION b/VERSION
index 9084fa2..227cea2 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-1.1.0
+2.0.0
diff --git a/handlers.go b/handlers.go
index 2ca0499..f23e670 100644
--- a/handlers.go
+++ b/handlers.go
@@ -50,69 +50,107 @@
 		if sub.OnuSerialNumber == sadisRequestID {
 			log.Infof("Found subscriber with ID %s", sub.OnuSerialNumber)
 			sadisSubscriber := sadisSubscriber{
-				ID:                   sub.OnuSerialNumber,
-				CTag:                 sub.CTag,
-				STag:                 sub.STag,
-				NasPortID:            sub.NasPortID,
-				CircuitID:            sub.CircuitID,
-				RemoteID:             sub.RemoteID,
-				TechnologyProfileID:  sub.TechnologyProfileID,
+				ID:        sub.OnuSerialNumber,
+				NasPortID: sub.NasPortID,
+				CircuitID: sub.CircuitID,
+				RemoteID:  sub.RemoteID,
 			}
 
-			log.Debugf("Fetching bandwidth profiles for subscriber %s", sub.OnuSerialNumber)
+			log.Debugf("Fetching UNI Tag list for subscriber %s", sub.OnuSerialNumber)
 
-			dsBandwidthprofile := bandwidthprofile{}
-			err = c.getOneBandwidthProfileHandler(sub.DownstreamBandwidthProfile, &dsBandwidthprofile)
-			if err != nil {
-				log.Errorf("Cannot fetch downstream bandwidth profile %s for subscriber %s", strconv.Itoa(sub.DownstreamBandwidthProfile), sub.OnuSerialNumber)
-				http.Error(w, err.Error(), http.StatusInternalServerError)
-				return
-			}
-			if (bandwidthprofile{}) == dsBandwidthprofile {
-				// it's empty
+			unitaglist := sadisUnitaginfolist{}
+			for _, unitagid := range sub.UniTagListId {
+				utinfo := unitaginfo{}
+				err = c.getOneUniTagInfo(unitagid, &utinfo)
+				if err != nil {
+					log.Errorf("Cannot fetch UNI tag information%s for subscriber %s", strconv.Itoa(unitagid), sub.OnuSerialNumber)
+					http.Error(w, err.Error(), http.StatusInternalServerError)
+					return
+				}
+				if (unitaginfo{}) == utinfo {
+					// it's empty
+					log.WithFields(logrus.Fields{
+						"UniTagInfoId": unitagid,
+						"Subscriber":   sub.OnuSerialNumber,
+						"sadisId":      sadisRequestID,
+					}).Error("UNI Tag info not found in XOS")
+					http.Error(w, "UNI Tag info not found in XOS", http.StatusInternalServerError)
+					return
+				}
+				sadisUnitaginfo := sadisUnitaginfo{
+					UniTagMatch:          utinfo.UniTagMatch,
+					PonCTag:              utinfo.PonCTag,
+					PonSTag:              utinfo.PonSTag,
+					UsPonCTagPriority:    utinfo.UsPonCTagPriority,
+					UsPonSTagPriority:    utinfo.UsPonSTagPriority,
+					DsPonCTagPriority:    utinfo.DsPonCTagPriority,
+					DsPonSTagPriority:    utinfo.DsPonSTagPriority,
+					TechnologyProfileID:  utinfo.TechnologyProfileID,
+					ServiceName:          utinfo.ServiceName,
+					EnableMacLearning:    utinfo.EnableMacLearning,
+					ConfiguredMacAddress: utinfo.ConfiguredMacAddress,
+					IsDhcpRequired:       utinfo.IsDhcpRequired,
+					IsIgmpRequired:       utinfo.IsIgmpRequired,
+				}
+
+				log.Debugf("Fetching bandwidth profiles for subscriber %s and unitagid: %s", sub.OnuSerialNumber, strconv.Itoa(utinfo.ID))
+
+				dsBandwidthprofile := bandwidthprofile{}
+				err = c.getOneBandwidthProfileHandler(utinfo.DownstreamBandwidthProfile, &dsBandwidthprofile)
+				if err != nil {
+					log.Errorf("Cannot fetch downstream bandwidth profile %s for subscriber %s", strconv.Itoa(utinfo.DownstreamBandwidthProfile), sub.OnuSerialNumber)
+					http.Error(w, err.Error(), http.StatusInternalServerError)
+					return
+				}
+				if (bandwidthprofile{}) == dsBandwidthprofile {
+					// it's empty
+					log.WithFields(logrus.Fields{
+						"DownstreamBandwidthProfile": utinfo.DownstreamBandwidthProfile,
+						"Subscriber":                 sub.OnuSerialNumber,
+						"sadisId":                    sadisRequestID,
+					}).Error("Downstream bandwidth profile not found in XOS")
+					http.Error(w, "Downstream bandwidth profile not found in XOS", http.StatusInternalServerError)
+					return
+				}
+				sadisUnitaginfo.DownstreamBandwidthProfile = dsBandwidthprofile.Name
+
+				usBandwidthprofile := bandwidthprofile{}
+				err = c.getOneBandwidthProfileHandler(utinfo.UpstreamBandwidthProfile, &usBandwidthprofile)
+				if err != nil {
+					log.Errorf("Cannot fetch upstream bandwidth profile %s for subscriber %s", strconv.Itoa(utinfo.UpstreamBandwidthProfile), sub.OnuSerialNumber)
+					http.Error(w, err.Error(), http.StatusInternalServerError)
+					return
+				}
+				if (bandwidthprofile{}) == usBandwidthprofile {
+					// it's empty
+					log.WithFields(logrus.Fields{
+						"UpstreamBandwidthProfile": utinfo.UpstreamBandwidthProfile,
+						"Subscriber":               sub.OnuSerialNumber,
+						"sadisId":                  sadisRequestID,
+					}).Error("Upstream bandwidth profile not found in XOS")
+					http.Error(w, "Upstream bandwidth profile not found in XOS", http.StatusInternalServerError)
+					return
+				}
+				sadisUnitaginfo.UpstreamBandwidthProfile = usBandwidthprofile.Name
+
 				log.WithFields(logrus.Fields{
-					"DownstreamBandwidthProfile": sub.DownstreamBandwidthProfile,
 					"Subscriber":                 sub.OnuSerialNumber,
-					"sadisId":                    sadisRequestID,
-				}).Error("Downstream bandwidth profile not found in XOS")
-				http.Error(w, "Downstream bandwidth profile not found in XOS", http.StatusInternalServerError)
-				return
+					"UniTagInfo":                 utinfo.ID,
+					"UpstreamBandwidthProfile":   usBandwidthprofile.Name,
+					"DownstreamBandwidthProfile": dsBandwidthprofile.Name,
+					"sadisId": sadisRequestID,
+				}).Debug("Bandwidth profiles for subscriber/unitaginfo")
+				unitaglist.SadisUniTagList = append(unitaglist.SadisUniTagList, &sadisUnitaginfo)
 			}
-			sadisSubscriber.DownstreamBandwidthProfile = dsBandwidthprofile.Name
+			sadisSubscriber.UniTagList = unitaglist.SadisUniTagList
 
-			usBandwidthprofile := bandwidthprofile{}
-			err = c.getOneBandwidthProfileHandler(sub.UpstreamBandwidthProfile, &usBandwidthprofile)
-			if err != nil {
-				log.Errorf("Cannot fetch upstream bandwidth profile %s for subscriber %s", strconv.Itoa(sub.UpstreamBandwidthProfile), sub.OnuSerialNumber)
-				http.Error(w, err.Error(), http.StatusInternalServerError)
-				return
-			}
-			if (bandwidthprofile{}) == usBandwidthprofile {
-				// it's empty
-				log.WithFields(logrus.Fields{
-					"UpstreamBandwidthProfile": usBandwidthprofile.Name,
-					"Subscriber":               sub.OnuSerialNumber,
-					"sadisId":                  sadisRequestID,
-				}).Error("Upstream bandwidth profile not found in XOS")
-				http.Error(w, "Upstream bandwidth profile not found in XOS", http.StatusInternalServerError)
-				return
-			}
-			sadisSubscriber.UpstreamBandwidthProfile = usBandwidthprofile.Name
-
-			log.WithFields(logrus.Fields{
-				"UpstreamBandwidthProfile":   usBandwidthprofile.Name,
-				"DownstreamBandwidthProfile": dsBandwidthprofile.Name,
-				"Subscriber":                 sub.OnuSerialNumber,
-				"sadisId":                    sadisRequestID,
-			}).Debug("Bandwidth profiles for subscriber")
-
-			json, e := json.Marshal(&sadisSubscriber)
+			sadisjson, e := json.Marshal(&sadisSubscriber)
 			if e != nil {
 				log.Errorf("Unable to marshal JSON: %s", e)
 				http.Error(w, e.Error(), http.StatusInternalServerError)
 				return
 			}
-			w.Write(json)
+			w.Write(sadisjson)
 			return
 		}
 	}
@@ -228,6 +266,15 @@
 	return nil
 }
 
+func (c *Config) getOneUniTagInfo(id int, data interface{}) error {
+	err := c.fetch("/xosapi/v1/rcord/rcordunitaginformations/"+strconv.Itoa(id), &data)
+	if err != nil {
+		log.Errorf("Unable to retrieve UNI Tag information from XOS: %s", err)
+		return err
+	}
+	return nil
+}
+
 func toInt(value string) int {
 	r, _ := strconv.Atoi(value)
 	return r
diff --git a/sadisTypes.go b/sadisTypes.go
index e0cc5be..c2a2546 100644
--- a/sadisTypes.go
+++ b/sadisTypes.go
@@ -27,31 +27,23 @@
   ONOS SADIS subscriber format
 */
 type sadisSubscriber struct {
-	ID                         string `json:"id"`
-	CTag                       int16  `json:"cTag"`
-	STag                       int16  `json:"sTag"`
-	NasPortID                  string `json:"nasPortId"`
-	CircuitID                  string `json:"circuitId"`
-	RemoteID                   string `json:"remoteId"`
-	UpstreamBandwidthProfile   string `json:"upstreamBandwidthProfile"`
-	DownstreamBandwidthProfile string `json:"downstreamBandwidthProfile"`
-	TechnologyProfileID        int    `json:"technologyProfileId"`
+	ID         string             `json:"id"`
+	NasPortID  string             `json:"nasPortId"`
+	CircuitID  string             `json:"circuitId"`
+	RemoteID   string             `json:"remoteId"`
+	UniTagList []*sadisUnitaginfo `json:"uniTagList"`
 }
 
 /*
   XOS RCORD subscriber format
 */
 type subscriber struct {
-	ID                         int    `json:"id"`
-	CTag                       int16  `json:"c_tag"`
-	STag                       int16  `json:"s_tag"`
-	OnuSerialNumber            string `json:"onu_device"`
-	NasPortID                  string `json:"nas_port_id"`
-	CircuitID                  string `json:"circuit_id"`
-	RemoteID                   string `json:"remote_id"`
-	UpstreamBandwidthProfile   int    `json:"upstream_bps_id"`
-	DownstreamBandwidthProfile int    `json:"downstream_bps_id"`
-	TechnologyProfileID        int    `json:"tech_profile_id"`
+	ID              int    `json:"id"`
+	OnuSerialNumber string `json:"onu_device"`
+	NasPortID       string `json:"nas_port_id"`
+	CircuitID       string `json:"circuit_id"`
+	RemoteID        string `json:"remote_id"`
+	UniTagListId    []int  `json:"unitaglist_ids"`
 }
 
 type subscribers struct {
@@ -59,6 +51,57 @@
 }
 
 /*
+  ONOS SADIS UNI Tag information format
+*/
+type sadisUnitaginfo struct {
+	//FIXME: which fields can be omitted??
+	UniTagMatch                int16  `json:"uniTagMatch"`
+	PonCTag                    int16  `json:"ponCTag"`
+	PonSTag                    int16  `json:"ponSTag"`
+	UsPonCTagPriority          int    `json:"usPonCTagPriority"`
+	UsPonSTagPriority          int    `json:"usPonSTagPriority"`
+	DsPonCTagPriority          int    `json:"dsPonCTagPriority"`
+	DsPonSTagPriority          int    `json:"dsPonSTagPriority"`
+	TechnologyProfileID        int    `json:"technologyProfileId"`
+	UpstreamBandwidthProfile   string `json:"upstreamBandwidthProfile"`
+	DownstreamBandwidthProfile string `json:"downstreamBandwidthProfile"`
+	ServiceName                string `json:"serviceName"`
+	EnableMacLearning          bool   `json:"enableMacLearning"`
+	ConfiguredMacAddress       *string `json:"configuredMacAddress,omitempty"`
+	IsDhcpRequired             bool   `json:"isDhcpRequired"`
+	IsIgmpRequired             bool   `json:"isIgmpRequired"`
+}
+
+type sadisUnitaginfolist struct {
+	SadisUniTagList []*sadisUnitaginfo `json:"items"`
+}
+
+/*
+  XOS RCORD UNI Tag information format
+*/
+
+type unitaginfo struct {
+	//FIXME: which fields can be empty and must be NOT be propagated? (for example see configured_mac_address)
+	ID                         int    `json:"id"`
+	UniTagMatch                int16  `json:"uni_tag_match"`
+	PonCTag                    int16  `json:"pon_c_tag"`
+	PonSTag                    int16  `json:"pon_s_tag"`
+	UsPonCTagPriority          int    `json:"us_pon_ctag_priority"`
+	UsPonSTagPriority          int    `json:"us_pon_stag_priority"`
+	DsPonCTagPriority          int    `json:"ds_pon_ctag_priority"`
+	DsPonSTagPriority          int    `json:"ds_pon_stag_priority"`
+	TechnologyProfileID        int    `json:"tech_profile_id"`
+	UpstreamBandwidthProfile   int    `json:"upstream_bps_id"`
+	DownstreamBandwidthProfile int    `json:"downstream_bps_id"`
+	ServiceName                string `json:"service_name"`
+	EnableMacLearning          bool   `json:"enable_mac_learning"`
+	ConfiguredMacAddress       *string `json:"configured_mac_address"`
+	IsDhcpRequired             bool   `json:"is_dhcp_required"`
+	IsIgmpRequired             bool   `json:"is_igmp_required"`
+	Subscriber                 int    `json:"subscriber_id"`
+}
+
+/*
   XOS BandwidthProfile format
 */
 type bandwidthprofile struct {