/*
   Copyright 2017 the original author or authors.

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

        http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

package physical

import "fmt"

/*
PONPort represents a single PON port on the OLT chassis
*/
type PONPort struct {
	Number   int
	DeviceID string
	Onts     [64]Ont
	Parent   *Edgecore `json:"-"`
}

/*
AllReadyActiveError - thrown when an attempt to activate a ONT which is already activated
*/
type AllReadyActiveError struct {
	slotNum    int
	clli       string
	ponportNum int
	ontNumber  int
}

/*
Error - the interface method that must be implemented on error
*/
func (e *AllReadyActiveError) Error() string {
	return fmt.Sprintf("Attempt to Activate ONT %d on PONPort %d Slot %d on %s but already active", e.ontNumber, e.ponportNum, e.slotNum, e.clli)
}

/*
AllReadyDeactivatedError - thrown when an attempt to activate a ONT which is already activated
*/
type AllReadyDeactivatedError struct {
	slotNum    int
	clli       string
	ponportNum int
	ontNumber  int
}

/*
Error - the interface method that must be implemented on error
*/
func (e *AllReadyDeactivatedError) Error() string {
	return fmt.Sprintf("Attempt to De-Activate ONT %d on PONPort %d Slot %d on %s but not active", e.ontNumber, e.ponportNum, e.slotNum, e.clli)
}

/*
ActivateOnt - passes ont information to chassis to make call to NEM to activate (whitelist) ont
*/
func (port *PONPort) ActivateOnt(number int, sVlan int, cVlan int, serialNumber string) error {
	slot := port.Parent
	chassis := slot.Parent
	fmt.Printf("Calling ActivateOnt and port state is %t\n", port.Onts[number-1].Active)

	if port.Onts[number-1].Active {
		e := AllReadyActiveError{ontNumber: number, slotNum: slot.Number, ponportNum: port.Number, clli: chassis.CLLI}
		return &e
	}
	ont := Ont{Number: number, Svlan: sVlan, Cvlan: cVlan, SerialNumber: serialNumber, Parent: port}
	port.Onts[number-1] = ont
	port.Parent.Parent.provisionONT(ont)
	port.Onts[number-1].Active = true
	return nil

}

/*
DeleteOnt - passes ont information to chassis to make call to NEM to de-activate (de-whitelist) ont
*/
func (port *PONPort) DeleteOnt(number int, sVlan int, cVlan int, serialNumber string) error {
	slot := port.Parent
	chassis := slot.Parent
	fmt.Printf("Calling ActivateOnt and port state is %t\n", port.Onts[number-1].Active)
	if port.Onts[number-1].Active != true {
		e := AllReadyDeactivatedError{ontNumber: number, slotNum: slot.Number, ponportNum: port.Number, clli: chassis.CLLI}
		return &e
	}
	ont := Ont{Number: number, Svlan: sVlan, Cvlan: cVlan, SerialNumber: serialNumber, Parent: port}
	chassis.deleteONT(ont)
	port.Onts[number-1].Active = false

	return nil
}
