/*
 * Copyright 2018-present Open Networking Foundation

 * 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 core

import (
	"github.com/opencord/voltha-bbsim/common/logger"
	"github.com/opencord/voltha-bbsim/device"
	"github.com/opencord/voltha-bbsim/flow"
	openolt "github.com/opencord/voltha-protos/go/openolt"
)

func sendOltIndUp(stream openolt.Openolt_EnableIndicationServer, olt *device.Olt) error {
	data := &openolt.Indication_OltInd{OltInd: &openolt.OltIndication{OperState: olt.OperState}}
	if err := stream.Send(&openolt.Indication{Data: data}); err != nil {
		logger.Error("Failed to send OLT UP indication: %v", err)
		return err
	}
	return nil
}

func sendOltIndDown(stream openolt.Openolt_EnableIndicationServer) error {
	data := &openolt.Indication_OltInd{OltInd: &openolt.OltIndication{OperState: "down"}}
	if err := stream.Send(&openolt.Indication{Data: data}); err != nil {
		logger.Error("Failed to send OLT DOWN indication: %v", err)
		return err
	}
	return nil
}

func sendIntfInd(stream openolt.Openolt_EnableIndicationServer, olt *device.Olt) error {
	// There is no need to send IntfInd for NNI
	for i := uint32(0); i < olt.NumPonIntf; i++ {
		intf := olt.PonIntfs[i]
		data := &openolt.Indication_IntfInd{IntfInd: &openolt.IntfIndication{IntfId: intf.IntfID, OperState: intf.OperState}}
		if err := stream.Send(&openolt.Indication{Data: data}); err != nil {
			logger.Error("Failed to send Intf [id: %d] indication : %v", i, err)
			return err
		}
		logger.Info("SendIntfInd olt:%d intf:%d (%s)", olt.ID, intf.IntfID, intf.Type)
	}
	return nil
}

func sendOperInd(stream openolt.Openolt_EnableIndicationServer, olt *device.Olt) error {
	// Send OperInd for Nni
	for i := uint32(0); i < olt.NumNniIntf; i++ {
		intf := olt.NniIntfs[i]
		data := &openolt.Indication_IntfOperInd{IntfOperInd: &openolt.IntfOperIndication{Type: intf.Type, IntfId: intf.IntfID, OperState: intf.OperState}}
		if err := stream.Send(&openolt.Indication{Data: data}); err != nil {
			logger.Error("Failed to send NNI IntfOper [id: %d] indication : %v", i, err)
			return err
		}
		logger.Info("SendOperInd NNI olt:%d intf:%d (%s)", olt.ID, intf.IntfID, intf.Type)
	}

	// Send OperInd for Pon
	for i := uint32(0); i < olt.NumPonIntf; i++ {
		intf := olt.PonIntfs[i]
		data := &openolt.Indication_IntfOperInd{IntfOperInd: &openolt.IntfOperIndication{Type: intf.Type, IntfId: intf.IntfID, OperState: intf.OperState}}
		if err := stream.Send(&openolt.Indication{Data: data}); err != nil {
			logger.Error("Failed to send PON IntfOper [id: %d] indication : %v", i, err)
			return err
		}
		logger.Info("SendOperInd PON olt:%d intf:%d (%s)", olt.ID, intf.IntfID, intf.Type)
	}
	return nil
}

func sendOnuDiscInd(stream openolt.Openolt_EnableIndicationServer, onu *device.Onu) error {
	data := &openolt.Indication_OnuDiscInd{OnuDiscInd: &openolt.OnuDiscIndication{IntfId: onu.IntfID, SerialNumber: onu.SerialNumber}}
	if err := stream.Send(&openolt.Indication{Data: data}); err != nil {
		logger.Error("Failed to send ONUDiscInd [id: %d]: %v", onu.OnuID, err)
		return err
	}
	device.LoggerWithOnu(onu).Info("sendONUDiscInd Onuid")
	return nil
}

func sendOnuInd(stream openolt.Openolt_EnableIndicationServer, onu *device.Onu, operState string, adminState string) error {
	data := &openolt.Indication_OnuInd{OnuInd: &openolt.OnuIndication{
		IntfId:       onu.IntfID,
		OnuId:        onu.OnuID,
		OperState:    operState,
		AdminState:   adminState,
		SerialNumber: onu.SerialNumber,
	}}
	if err := stream.Send(&openolt.Indication{Data: data}); err != nil {
		logger.Error("Failed to send ONUInd [id: %d]: %v", onu.OnuID, err)
		return err
	}
	device.LoggerWithOnu(onu).Info("sendONUInd Onuid")
	return nil
}

func sendDyingGaspInd(stream openolt.Openolt_EnableIndicationServer, intfID uint32, onuID uint32) error {
	// Form DyingGasp Indication with ONU-ID and Intf-ID
	alarmData := &openolt.AlarmIndication_DyingGaspInd{DyingGaspInd: &openolt.DyingGaspIndication{IntfId: intfID, OnuId: onuID, Status: "on"}}
	data := &openolt.Indication_AlarmInd{AlarmInd: &openolt.AlarmIndication{Data: alarmData}}

	// Send Indication to VOLTHA
	if err := stream.Send(&openolt.Indication{Data: data}); err != nil {
		logger.Error("Failed to send DyingGaspInd : %v", err)
		return err
	}
	logger.Info("sendDyingGaspInd Intf-ID:%d ONU-ID:%d", intfID, onuID)
	return nil
}

func startAlarmLoop(stream openolt.Openolt_EnableIndicationServer, alarmchan chan *openolt.Indication) {
	logger.Debug("SendAlarm() Invoked")
	for {
		select {
		case ind := <-alarmchan:
			logger.Debug("Alarm recieved at alarm-channel to send to voltha %+v", ind)
			err := stream.Send(ind)
			if err != nil {
				logger.Debug("Error occured while sending alarm indication %v", err)
			}
		}
	}
}

func sendPortStats(stream openolt.Openolt_EnableIndicationServer, port *device.Port) error {
	portStats := flow.GetPortStats(&port.PortStats)
	portStats.IntfId = interfaceIDToPortNo(port.IntfID, port.Type)
	data := &openolt.Indication_PortStats{
		PortStats: portStats,
	}
	return stream.Send(&openolt.Indication{Data: data})
}
