package models

import (
	"strings"
	"time"
)

// ToFrontend converts a State to StateFrontend
func (s *State) ToFrontend() StateFrontend {
	return s.GetSnapshot().ToFrontend()
}

// ToFrontend converts a Node to NodeFrontend
func (n Node) ToFrontend() NodeFrontend {
	nf := NodeFrontend{
		ID:                           n.ID,
		Node:                         n.Name,
		Name:                         n.Name,
		DisplayName:                  n.DisplayName,
		Instance:                     n.Instance,
		Host:                         n.Host,
		Status:                       n.Status,
		Type:                         n.Type,
		CPU:                          n.CPU,
		Mem:                          n.Memory.Used,
		MaxMem:                       n.Memory.Total,
		MaxDisk:                      n.Disk.Total,
		Uptime:                       n.Uptime,
		LoadAverage:                  n.LoadAverage,
		KernelVersion:                n.KernelVersion,
		PVEVersion:                   n.PVEVersion,
		CPUInfo:                      n.CPUInfo,
		LastSeen:                     n.LastSeen.Unix() * 1000,
		ConnectionHealth:             n.ConnectionHealth,
		IsClusterMember:              n.IsClusterMember,
		ClusterName:                  n.ClusterName,
		TemperatureMonitoringEnabled: n.TemperatureMonitoringEnabled,
	}

	// Include full Memory object if it has data
	if n.Memory.Total > 0 {
		nf.Memory = &n.Memory
	}

	// Include full Disk object if it has data
	if n.Disk.Total > 0 {
		nf.Disk = &n.Disk
	}

	// Include temperature data if available
	if n.Temperature != nil && n.Temperature.Available {
		nf.Temperature = n.Temperature
	}

	if nf.DisplayName == "" {
		nf.DisplayName = nf.Name
	}

	return nf
}

// ToFrontend converts a VM to VMFrontend
func (v VM) ToFrontend() VMFrontend {
	vm := VMFrontend{
		ID:               v.ID,
		VMID:             v.VMID,
		Name:             v.Name,
		Node:             v.Node,
		Instance:         v.Instance,
		Status:           v.Status,
		Type:             v.Type,
		CPU:              v.CPU,
		CPUs:             v.CPUs,
		Mem:              v.Memory.Used,
		MaxMem:           v.Memory.Total,
		NetIn:            zeroIfNegative(v.NetworkIn),
		NetOut:           zeroIfNegative(v.NetworkOut),
		DiskRead:         zeroIfNegative(v.DiskRead),
		DiskWrite:        zeroIfNegative(v.DiskWrite),
		Uptime:           v.Uptime,
		Template:         v.Template,
		Lock:             v.Lock,
		LastSeen:         v.LastSeen.Unix() * 1000,
		DiskStatusReason: v.DiskStatusReason,
	}

	// Convert tags array to string
	if len(v.Tags) > 0 {
		vm.Tags = strings.Join(v.Tags, ",")
	}

	// Convert last backup time if not zero
	if !v.LastBackup.IsZero() {
		vm.LastBackup = v.LastBackup.Unix() * 1000
	}

	// Include full Memory object if it has data
	if v.Memory.Total > 0 {
		vm.Memory = &v.Memory
	}

	// Include full Disk object if it has data
	if v.Disk.Total > 0 {
		vm.DiskObj = &v.Disk
	}

	// Include individual disks array if available
	if len(v.Disks) > 0 {
		vm.Disks = v.Disks
	}

	if len(v.IPAddresses) > 0 {
		vm.IPAddresses = append([]string(nil), v.IPAddresses...)
	}

	if v.OSName != "" {
		vm.OSName = v.OSName
	}

	if v.OSVersion != "" {
		vm.OSVersion = v.OSVersion
	}

	if v.AgentVersion != "" {
		vm.AgentVersion = v.AgentVersion
	}

	if len(v.NetworkInterfaces) > 0 {
		vm.NetworkInterfaces = make([]GuestNetworkInterface, len(v.NetworkInterfaces))
		copy(vm.NetworkInterfaces, v.NetworkInterfaces)
	}

	return vm
}

// ToFrontend converts a Container to ContainerFrontend
func (c Container) ToFrontend() ContainerFrontend {
	ct := ContainerFrontend{
		ID:        c.ID,
		VMID:      c.VMID,
		Name:      c.Name,
		Node:      c.Node,
		Instance:  c.Instance,
		Status:    c.Status,
		Type:      c.Type,
		CPU:       c.CPU,
		CPUs:      c.CPUs,
		Mem:       c.Memory.Used,
		MaxMem:    c.Memory.Total,
		NetIn:     zeroIfNegative(c.NetworkIn),
		NetOut:    zeroIfNegative(c.NetworkOut),
		DiskRead:  zeroIfNegative(c.DiskRead),
		DiskWrite: zeroIfNegative(c.DiskWrite),
		Uptime:    c.Uptime,
		Template:  c.Template,
		Lock:      c.Lock,
		LastSeen:  c.LastSeen.Unix() * 1000,
	}

	// Convert tags array to string
	if len(c.Tags) > 0 {
		ct.Tags = strings.Join(c.Tags, ",")
	}

	// Convert last backup time if not zero
	if !c.LastBackup.IsZero() {
		ct.LastBackup = c.LastBackup.Unix() * 1000
	}

	// Include full Memory object if it has data
	if c.Memory.Total > 0 {
		ct.Memory = &c.Memory
	}

	// Include full Disk object if it has data
	if c.Disk.Total > 0 {
		ct.DiskObj = &c.Disk
	}

	// Include individual disks array if available
	if len(c.Disks) > 0 {
		ct.Disks = c.Disks
	}

	if len(c.IPAddresses) > 0 {
		ct.IPAddresses = append([]string(nil), c.IPAddresses...)
	}

	if len(c.NetworkInterfaces) > 0 {
		ct.NetworkInterfaces = make([]GuestNetworkInterface, len(c.NetworkInterfaces))
		copy(ct.NetworkInterfaces, c.NetworkInterfaces)
	}

	return ct
}

// ToFrontend converts a DockerHost to DockerHostFrontend
func (d DockerHost) ToFrontend() DockerHostFrontend {
	h := DockerHostFrontend{
		ID:                d.ID,
		AgentID:           d.AgentID,
		Hostname:          d.Hostname,
		DisplayName:       d.DisplayName,
		CustomDisplayName: d.CustomDisplayName,
		MachineID:         d.MachineID,
		OS:                d.OS,
		KernelVersion:     d.KernelVersion,
		Architecture:      d.Architecture,
		Runtime:           d.Runtime,
		RuntimeVersion:    d.RuntimeVersion,
		DockerVersion:     d.DockerVersion,
		CPUs:              d.CPUs,
		TotalMemoryBytes:  d.TotalMemoryBytes,
		UptimeSeconds:     d.UptimeSeconds,
		CPUUsagePercent:   d.CPUUsage,
		Status:            d.Status,
		LastSeen:          d.LastSeen.Unix() * 1000,
		IntervalSeconds:   d.IntervalSeconds,
		AgentVersion:      d.AgentVersion,
		Containers:        make([]DockerContainerFrontend, len(d.Containers)),
	}

	if h.DisplayName == "" {
		h.DisplayName = h.Hostname
	}

	h.PendingUninstall = d.PendingUninstall

	if d.TokenID != "" {
		h.TokenID = d.TokenID
		h.TokenName = d.TokenName
		h.TokenHint = d.TokenHint
		if d.TokenLastUsedAt != nil && !d.TokenLastUsedAt.IsZero() {
			ts := d.TokenLastUsedAt.Unix() * 1000
			h.TokenLastUsedAt = &ts
		}
	}

	for i, ct := range d.Containers {
		h.Containers[i] = ct.ToFrontend()
	}

	if len(d.Services) > 0 {
		h.Services = make([]DockerServiceFrontend, len(d.Services))
		for i, svc := range d.Services {
			h.Services[i] = svc.ToFrontend()
		}
	}

	if len(d.Tasks) > 0 {
		h.Tasks = make([]DockerTaskFrontend, len(d.Tasks))
		for i, task := range d.Tasks {
			h.Tasks[i] = task.ToFrontend()
		}
	}

	if d.Swarm != nil {
		sw := d.Swarm.ToFrontend()
		h.Swarm = &sw
	}

	if len(d.LoadAverage) > 0 {
		h.LoadAverage = append([]float64(nil), d.LoadAverage...)
	}

	if (d.Memory != Memory{}) {
		mem := d.Memory
		h.Memory = &mem
	}

	if len(d.Disks) > 0 {
		h.Disks = append([]Disk(nil), d.Disks...)
	}

	if len(d.NetworkInterfaces) > 0 {
		h.NetworkInterfaces = make([]HostNetworkInterface, len(d.NetworkInterfaces))
		copy(h.NetworkInterfaces, d.NetworkInterfaces)
	}

	if d.Command != nil {
		h.Command = toDockerHostCommandFrontend(*d.Command)
	}

	return h
}

// ToFrontend converts a RemovedDockerHost to its frontend representation.
func (r RemovedDockerHost) ToFrontend() RemovedDockerHostFrontend {
	return RemovedDockerHostFrontend{
		ID:          r.ID,
		Hostname:    r.Hostname,
		DisplayName: r.DisplayName,
		RemovedAt:   r.RemovedAt.Unix() * 1000,
	}
}

// ToFrontend converts a Host to HostFrontend.
func (h Host) ToFrontend() HostFrontend {
	host := HostFrontend{
		ID:              h.ID,
		Hostname:        h.Hostname,
		DisplayName:     h.DisplayName,
		Platform:        h.Platform,
		OSName:          h.OSName,
		OSVersion:       h.OSVersion,
		KernelVersion:   h.KernelVersion,
		Architecture:    h.Architecture,
		CPUCount:        h.CPUCount,
		CPUUsage:        h.CPUUsage,
		Status:          h.Status,
		UptimeSeconds:   h.UptimeSeconds,
		IntervalSeconds: h.IntervalSeconds,
		AgentVersion:    h.AgentVersion,
		TokenID:         h.TokenID,
		TokenName:       h.TokenName,
		TokenHint:       h.TokenHint,
		Tags:            append([]string(nil), h.Tags...),
		LastSeen:        h.LastSeen.Unix() * 1000,
	}

	if host.DisplayName == "" {
		if h.DisplayName != "" {
			host.DisplayName = h.DisplayName
		} else if h.Hostname != "" {
			host.DisplayName = h.Hostname
		}
	}

	if len(h.LoadAverage) > 0 {
		host.LoadAverage = append([]float64(nil), h.LoadAverage...)
	}

	if (h.Memory != Memory{}) {
		mem := h.Memory
		host.Memory = &mem
	}

	if len(h.Disks) > 0 {
		host.Disks = append([]Disk(nil), h.Disks...)
	}

	if len(h.NetworkInterfaces) > 0 {
		host.NetworkInterfaces = make([]HostNetworkInterface, len(h.NetworkInterfaces))
		copy(host.NetworkInterfaces, h.NetworkInterfaces)
	}

	if s := hostSensorSummaryToFrontend(h.Sensors); s != nil {
		host.Sensors = s
	}

	if h.TokenLastUsedAt != nil && !h.TokenLastUsedAt.IsZero() {
		ts := h.TokenLastUsedAt.Unix() * 1000
		host.TokenLastUsedAt = &ts
	}

	return host
}

// ToFrontend converts a DockerContainer to DockerContainerFrontend
func (c DockerContainer) ToFrontend() DockerContainerFrontend {
	container := DockerContainerFrontend{
		ID:                  c.ID,
		Name:                c.Name,
		Image:               c.Image,
		State:               c.State,
		Status:              c.Status,
		Health:              c.Health,
		CPUPercent:          c.CPUPercent,
		MemoryUsage:         c.MemoryUsage,
		MemoryLimit:         c.MemoryLimit,
		MemoryPercent:       c.MemoryPercent,
		UptimeSeconds:       c.UptimeSeconds,
		RestartCount:        c.RestartCount,
		ExitCode:            c.ExitCode,
		CreatedAt:           c.CreatedAt.Unix() * 1000,
		Labels:              c.Labels,
		WritableLayerBytes:  c.WritableLayerBytes,
		RootFilesystemBytes: c.RootFilesystemBytes,
	}

	if c.StartedAt != nil {
		ms := c.StartedAt.Unix() * 1000
		container.StartedAt = &ms
	}

	if c.FinishedAt != nil {
		ms := c.FinishedAt.Unix() * 1000
		container.FinishedAt = &ms
	}

	if len(c.Ports) > 0 {
		ports := make([]DockerContainerPortFrontend, len(c.Ports))
		for i, port := range c.Ports {
			ports[i] = DockerContainerPortFrontend{
				PrivatePort: port.PrivatePort,
				PublicPort:  port.PublicPort,
				Protocol:    port.Protocol,
				IP:          port.IP,
			}
		}
		container.Ports = ports
	}

	if len(c.Networks) > 0 {
		networks := make([]DockerContainerNetworkFrontend, len(c.Networks))
		for i, net := range c.Networks {
			networks[i] = DockerContainerNetworkFrontend{
				Name: net.Name,
				IPv4: net.IPv4,
				IPv6: net.IPv6,
			}
		}
		container.Networks = networks
	}

	if c.BlockIO != nil {
		container.BlockIO = &DockerContainerBlockIOFrontend{
			ReadBytes:               c.BlockIO.ReadBytes,
			WriteBytes:              c.BlockIO.WriteBytes,
			ReadRateBytesPerSecond:  c.BlockIO.ReadRateBytesPerSecond,
			WriteRateBytesPerSecond: c.BlockIO.WriteRateBytesPerSecond,
		}
	}

	if len(c.Mounts) > 0 {
		mounts := make([]DockerContainerMountFrontend, len(c.Mounts))
		for i, mount := range c.Mounts {
			mounts[i] = DockerContainerMountFrontend{
				Type:        mount.Type,
				Source:      mount.Source,
				Destination: mount.Destination,
				Mode:        mount.Mode,
				RW:          mount.RW,
				Propagation: mount.Propagation,
				Name:        mount.Name,
				Driver:      mount.Driver,
			}
		}
		container.Mounts = mounts
	}

	if c.Podman != nil {
		container.Podman = &DockerPodmanContainerFrontend{
			PodName:           c.Podman.PodName,
			PodID:             c.Podman.PodID,
			Infra:             c.Podman.Infra,
			ComposeProject:    c.Podman.ComposeProject,
			ComposeService:    c.Podman.ComposeService,
			ComposeWorkdir:    c.Podman.ComposeWorkdir,
			ComposeConfigHash: c.Podman.ComposeConfigHash,
			AutoUpdatePolicy:  c.Podman.AutoUpdatePolicy,
			AutoUpdateRestart: c.Podman.AutoUpdateRestart,
			UserNamespace:     c.Podman.UserNamespace,
		}
	}

	return container
}

// ToFrontend converts a DockerService to DockerServiceFrontend.
func (s DockerService) ToFrontend() DockerServiceFrontend {
	service := DockerServiceFrontend{
		ID:             s.ID,
		Name:           s.Name,
		Stack:          s.Stack,
		Image:          s.Image,
		Mode:           s.Mode,
		DesiredTasks:   s.DesiredTasks,
		RunningTasks:   s.RunningTasks,
		CompletedTasks: s.CompletedTasks,
		Labels:         nil,
	}

	if len(s.Labels) > 0 {
		service.Labels = make(map[string]string, len(s.Labels))
		for k, v := range s.Labels {
			service.Labels[k] = v
		}
	}

	if len(s.EndpointPorts) > 0 {
		service.EndpointPorts = make([]DockerServicePortFrontend, len(s.EndpointPorts))
		for i, port := range s.EndpointPorts {
			service.EndpointPorts[i] = port.ToFrontend()
		}
	}

	if s.UpdateStatus != nil {
		update := s.UpdateStatus.ToFrontend()
		service.UpdateStatus = &update
	}

	if s.CreatedAt != nil && !s.CreatedAt.IsZero() {
		ts := s.CreatedAt.Unix() * 1000
		service.CreatedAt = &ts
	}
	if s.UpdatedAt != nil && !s.UpdatedAt.IsZero() {
		ts := s.UpdatedAt.Unix() * 1000
		service.UpdatedAt = &ts
	}

	return service
}

// ToFrontend converts a DockerServicePort to DockerServicePortFrontend.
func (p DockerServicePort) ToFrontend() DockerServicePortFrontend {
	return DockerServicePortFrontend{
		Name:          p.Name,
		Protocol:      p.Protocol,
		TargetPort:    p.TargetPort,
		PublishedPort: p.PublishedPort,
		PublishMode:   p.PublishMode,
	}
}

// ToFrontend converts a DockerServiceUpdate to DockerServiceUpdateFrontend.
func (u DockerServiceUpdate) ToFrontend() DockerServiceUpdateFrontend {
	update := DockerServiceUpdateFrontend{
		State:   u.State,
		Message: u.Message,
	}
	if u.CompletedAt != nil && !u.CompletedAt.IsZero() {
		ts := u.CompletedAt.Unix() * 1000
		update.CompletedAt = &ts
	}
	return update
}

// ToFrontend converts a DockerTask to DockerTaskFrontend.
func (t DockerTask) ToFrontend() DockerTaskFrontend {
	task := DockerTaskFrontend{
		ID:            t.ID,
		ServiceID:     t.ServiceID,
		ServiceName:   t.ServiceName,
		Slot:          t.Slot,
		NodeID:        t.NodeID,
		NodeName:      t.NodeName,
		DesiredState:  t.DesiredState,
		CurrentState:  t.CurrentState,
		Error:         t.Error,
		Message:       t.Message,
		ContainerID:   t.ContainerID,
		ContainerName: t.ContainerName,
	}

	if !t.CreatedAt.IsZero() {
		ts := t.CreatedAt.Unix() * 1000
		task.CreatedAt = &ts
	}
	if t.UpdatedAt != nil && !t.UpdatedAt.IsZero() {
		ts := t.UpdatedAt.Unix() * 1000
		task.UpdatedAt = &ts
	}
	if t.StartedAt != nil && !t.StartedAt.IsZero() {
		ts := t.StartedAt.Unix() * 1000
		task.StartedAt = &ts
	}
	if t.CompletedAt != nil && !t.CompletedAt.IsZero() {
		ts := t.CompletedAt.Unix() * 1000
		task.CompletedAt = &ts
	}

	return task
}

// ToFrontend converts DockerSwarmInfo to DockerSwarmFrontend.
func (s DockerSwarmInfo) ToFrontend() DockerSwarmFrontend {
	return DockerSwarmFrontend{
		NodeID:           s.NodeID,
		NodeRole:         s.NodeRole,
		LocalState:       s.LocalState,
		ControlAvailable: s.ControlAvailable,
		ClusterID:        s.ClusterID,
		ClusterName:      s.ClusterName,
		Scope:            s.Scope,
		Error:            s.Error,
	}
}

func hostSensorSummaryToFrontend(src HostSensorSummary) *HostSensorSummaryFrontend {
	if len(src.TemperatureCelsius) == 0 && len(src.FanRPM) == 0 && len(src.Additional) == 0 {
		return nil
	}

	dest := &HostSensorSummaryFrontend{}
	if len(src.TemperatureCelsius) > 0 {
		dest.TemperatureCelsius = copyStringFloatMap(src.TemperatureCelsius)
	}
	if len(src.FanRPM) > 0 {
		dest.FanRPM = copyStringFloatMap(src.FanRPM)
	}
	if len(src.Additional) > 0 {
		dest.Additional = copyStringFloatMap(src.Additional)
	}
	return dest
}

func copyStringFloatMap(src map[string]float64) map[string]float64 {
	if len(src) == 0 {
		return nil
	}
	dest := make(map[string]float64, len(src))
	for k, v := range src {
		dest[k] = v
	}
	return dest
}

func toDockerHostCommandFrontend(cmd DockerHostCommandStatus) *DockerHostCommandFrontend {
	result := &DockerHostCommandFrontend{
		ID:        cmd.ID,
		Type:      cmd.Type,
		Status:    cmd.Status,
		Message:   cmd.Message,
		CreatedAt: cmd.CreatedAt.Unix() * 1000,
		UpdatedAt: cmd.UpdatedAt.Unix() * 1000,
	}

	if cmd.DispatchedAt != nil {
		ms := cmd.DispatchedAt.Unix() * 1000
		result.DispatchedAt = &ms
	}
	if cmd.AcknowledgedAt != nil {
		ms := cmd.AcknowledgedAt.Unix() * 1000
		result.AcknowledgedAt = &ms
	}
	if cmd.CompletedAt != nil {
		ms := cmd.CompletedAt.Unix() * 1000
		result.CompletedAt = &ms
	}
	if cmd.FailedAt != nil {
		ms := cmd.FailedAt.Unix() * 1000
		result.FailedAt = &ms
	}
	if cmd.FailureReason != "" {
		result.FailureReason = cmd.FailureReason
	}
	if cmd.ExpiresAt != nil {
		ms := cmd.ExpiresAt.Unix() * 1000
		result.ExpiresAt = &ms
	}

	return result
}

// ToFrontend converts Storage to StorageFrontend
func (s Storage) ToFrontend() StorageFrontend {
	return StorageFrontend{
		ID:        s.ID,
		Storage:   s.Name,
		Name:      s.Name,
		Node:      s.Node,
		Instance:  s.Instance,
		Nodes:     s.Nodes,
		NodeIDs:   s.NodeIDs,
		NodeCount: s.NodeCount,
		Type:      s.Type,
		Status:    s.Status,
		Total:     s.Total,
		Used:      s.Used,
		Avail:     s.Free,
		Free:      s.Free,
		Usage:     s.Usage,
		Content:   s.Content,
		Shared:    s.Shared,
		Enabled:   s.Enabled,
		Active:    s.Active,
	}
}

// ToFrontend converts a CephCluster to CephClusterFrontend
func (c CephCluster) ToFrontend() CephClusterFrontend {
	frontend := CephClusterFrontend{
		ID:             c.ID,
		Instance:       c.Instance,
		Name:           c.Name,
		FSID:           c.FSID,
		Health:         c.Health,
		HealthMessage:  c.HealthMessage,
		TotalBytes:     c.TotalBytes,
		UsedBytes:      c.UsedBytes,
		AvailableBytes: c.AvailableBytes,
		UsagePercent:   c.UsagePercent,
		NumMons:        c.NumMons,
		NumMgrs:        c.NumMgrs,
		NumOSDs:        c.NumOSDs,
		NumOSDsUp:      c.NumOSDsUp,
		NumOSDsIn:      c.NumOSDsIn,
		NumPGs:         c.NumPGs,
		LastUpdated:    c.LastUpdated.Unix() * 1000,
	}

	if len(c.Pools) > 0 {
		frontend.Pools = append([]CephPool(nil), c.Pools...)
	}

	if len(c.Services) > 0 {
		frontend.Services = append([]CephServiceStatus(nil), c.Services...)
	}

	return frontend
}

// ToFrontend converts a replication job to a frontend representation.
func (r ReplicationJob) ToFrontend() ReplicationJobFrontend {
	frontend := ReplicationJobFrontend{
		ID:                      r.ID,
		Instance:                r.Instance,
		JobID:                   r.JobID,
		JobNumber:               r.JobNumber,
		Guest:                   r.Guest,
		GuestID:                 r.GuestID,
		GuestName:               r.GuestName,
		GuestType:               r.GuestType,
		GuestNode:               r.GuestNode,
		SourceNode:              r.SourceNode,
		SourceStorage:           r.SourceStorage,
		TargetNode:              r.TargetNode,
		TargetStorage:           r.TargetStorage,
		Schedule:                r.Schedule,
		Type:                    r.Type,
		Enabled:                 r.Enabled,
		State:                   r.State,
		Status:                  r.Status,
		LastSyncStatus:          r.LastSyncStatus,
		LastSyncUnix:            r.LastSyncUnix,
		LastSyncDurationSeconds: r.LastSyncDurationSeconds,
		LastSyncDurationHuman:   r.LastSyncDurationHuman,
		NextSyncUnix:            r.NextSyncUnix,
		DurationSeconds:         r.DurationSeconds,
		DurationHuman:           r.DurationHuman,
		FailCount:               r.FailCount,
		Error:                   r.Error,
		Comment:                 r.Comment,
		RemoveJob:               r.RemoveJob,
		RateLimitMbps:           r.RateLimitMbps,
	}

	if r.LastSyncTime != nil {
		frontend.LastSyncTime = r.LastSyncTime.UnixMilli()
	}

	if r.NextSyncTime != nil {
		frontend.NextSyncTime = r.NextSyncTime.UnixMilli()
	}

	polledAt := r.LastPolled
	if polledAt.IsZero() {
		polledAt = time.Now()
	}
	frontend.PolledAt = polledAt.UnixMilli()

	return frontend
}

// zeroIfNegative returns 0 for negative values (used for I/O metrics)
func zeroIfNegative(val int64) int64 {
	if val < 0 {
		return 0
	}
	return val
}
