using System;
using System.Collections.Generic;
using Valg.EVA.Skanning.Contracts.CommonEnums;

namespace Valg.EVA.Skanning.Entity.SerializedEntities.CountResultModel
{
    public class CastVote
    {
        private AffiliationIdentifier affiliationIdentifier;
        private RejectionReasonCode proposedRejection;
        private bool inDoubt;

        public CastVote()
        {
            Renumberings = new List<Renumber>();
            Strikeouts = new List<Strikeout>();
            WriteIns = new List<WriteIn>();
            PersonalVotes = new List<PersonalVote>();
        }

        
        
        
        public enum RejectionReasonCode
        {
            
            
            
            NotRejected = 0,

            
            
            
            FA,

            
            
            
            FB,

            
            
            
            FC,

            
            
            
            FD,

            
            
            
            VA,

            
            
            
            VB,

            
            
            
            VC,

            
            
            
            VD
        }

        public string VotingCategory { get; set; }

        public string ElectionEventId { get; set; }

        public string AreaContextId { get; set; }

        public string ContestId { get; set; }

        public string ElectionIdentifier { get; set; }

        public string ElectionGroup { get; set; }

        public int BallotDbId { get; set; }

        public AffiliationIdentifier AffiliationIdentifier
        {
            get { return affiliationIdentifier; }
            set
            {
                AssertAffiliationAndRejectionReasonMutualExclusive(value, ProposedRejection);
                AssertAffiliationAndInDoubtMutualExclusive(value, InDoubt);
                affiliationIdentifier = value;
            }
        }

        private void AssertAffiliationAndRejectionReasonMutualExclusive(AffiliationIdentifier affiliation, RejectionReasonCode proposedRejectionValue)
        {
            if(proposedRejectionValue != RejectionReasonCode.NotRejected && affiliation != null)
                throw new InvalidOperationException(string.Format("An attempt was made to set affiliation and rejectionReason on a CastVote-object. This is not allowed. BallotPaperId = {0}", BallotDbId));
        }

        public RejectionReasonCode ProposedRejection
        {
            get { return proposedRejection; }
            set
            {
                AssertAffiliationAndRejectionReasonMutualExclusive(AffiliationIdentifier, value);
                proposedRejection = value;
            }
        }

        public string ReportingUnitIdentifier { get; set; }

        public List<PersonalVote> PersonalVotes { get; set; }

        public List<WriteIn> WriteIns { get; set; }

        public List<Renumber> Renumberings { get; set; }

        public List<Strikeout> Strikeouts { get; set; }

        public bool InDoubt
        {
            get { return inDoubt; }
            set
            {
                AssertAffiliationAndInDoubtMutualExclusive(AffiliationIdentifier, value);
                inDoubt = value;
            }
        }

        private void AssertAffiliationAndInDoubtMutualExclusive(AffiliationIdentifier affiliation, bool inDoubtValue)
        {
            if(inDoubtValue && affiliation != null)
                throw new InvalidOperationException(string.Format("An attempt was made to set affiliation and InDoubt = true on a CastVote-object. This is not allowed. BallotPaperId = {0}", BallotDbId));
        }

        public CountingType CountingType { get; set; }

        public bool IsModified
        {
            get { return HasPersonalVotes || HasWriteIns || HasRenumberings || HasStrikeouts; }

        }

        public bool HasPersonalVotes
        {
            get { return PersonalVotes != null && PersonalVotes.Count > 0; }
        }

        public bool HasWriteIns
        {
            get { return WriteIns != null && WriteIns.Count > 0; }
        }

        public bool HasRenumberings
        {
            get { return Renumberings != null && Renumberings.Count > 0; }
        }
        public bool HasStrikeouts
        {
            get { return Strikeouts != null && Strikeouts.Count > 0; }
        }
    }
}
