// SSimControl.cpp : implementation file
//

#include "stdafx.h"
#include "Simulator.h"
#include "SSimControl.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// SSimControl dialog


SSimControl::SSimControl(CWnd* pParent /*=NULL*/)
	: CDialog(SSimControl::IDD, pParent)
{
	//{{AFX_DATA_INIT(SSimControl)
	m_RenderSpeed = 0;
	m_SimulationSpeed = 0;
	m_RealSensorScale = FALSE;
	m_SpeedOfSound = 0.0f;
	m_SonarStreamAngle = 0.0f;
	m_SonarBeamAngle = 0.0f;
	m_NSonarPastBeams = 0;
	m_RSonarPastBeams = FALSE;
	m_RSonarPastCollisions = FALSE;
	m_FollowModel = FALSE;
	m_SonarMaxDistance = 0.0f;
	m_ExtraFlipping = FALSE;
	m_IRNonIdeality = 0;
	m_SimMultiplier = 0.0f;
	//}}AFX_DATA_INIT
    m_pParent = pParent;  // used to enable the modeless dialog, don't ask!
	m_nID = SSimControl::IDD;    
}


void SSimControl::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(SSimControl)
	DDX_Control(pDX, IDC_SPINIR, m_IRSpin);
	DDX_Control(pDX, IDC_RENDERSPEEDSLDR, m_RenderSpeedSldr);
	DDX_Control(pDX, IDC_SIMULATIONSPEEDSLDR, m_SimulationSpeedSldr);
	DDX_Text(pDX, IDC_RENDERSPEED, m_RenderSpeed);
	DDV_MinMaxInt(pDX, m_RenderSpeed, MINRENDERSPEED, MAXRENDERSPEED);
	DDX_Text(pDX, IDC_SIMULATIONSPEED, m_SimulationSpeed);
	DDV_MinMaxInt(pDX, m_SimulationSpeed, MINSIMSPEED, MAXSIMSPEED);
	DDX_Check(pDX, IDC_RSENSORS, m_RealSensorScale);
	DDX_Text(pDX, IDC_SPEEDOFSOUND, m_SpeedOfSound);
	DDV_MinMaxFloat(pDX, m_SpeedOfSound, MINSPEEDOFSOUND, MAXSPEEDOFSOUND);
	DDX_Text(pDX, IDC_SONARSTREAMANGLE, m_SonarStreamAngle);
	DDV_MinMaxFloat(pDX, m_SonarStreamAngle, MINSTREAMANGLE, MAXSTREAMANGLE);
	DDX_Text(pDX, IDC_SONARBEAMANGLE, m_SonarBeamAngle);
	DDV_MinMaxFloat(pDX, m_SonarBeamAngle, MINSONARBEAMANGLE, MAXSONARBEAMANGLE);
	DDX_Text(pDX, IDC_NSonarPastBeams, m_NSonarPastBeams);
	DDV_MinMaxInt(pDX, m_NSonarPastBeams, MINNPASTBEAMS, MAXNPASTBEAMS);
	DDX_Check(pDX, IDC_RSONARPASTBEAMS, m_RSonarPastBeams);
	DDX_Check(pDX, IDC_RSONARPASTCOLLISIONS, m_RSonarPastCollisions);
	DDX_Check(pDX, IDC_FOLLOWMODEL, m_FollowModel);
	DDX_Text(pDX, IDC_SONARMAXDISTANCE, m_SonarMaxDistance);
	DDV_MinMaxFloat(pDX, m_SonarMaxDistance, MINMAXSONARDISTANCE, MAXMAXSONARDISTANCE);
	DDX_Check(pDX, IDC_EXTRAFLIPPING, m_ExtraFlipping);
	DDX_Text(pDX, IDC_IRNONIDEALITY, m_IRNonIdeality);
	DDV_MinMaxInt(pDX, m_IRNonIdeality, MINIRNONIDEALITY, MAXIRNONIDEALITY);
	DDX_Text(pDX, IDC_SIMMULTIPLIER, m_SimMultiplier);
	DDV_MinMaxFloat(pDX, m_SimMultiplier, MINSIMMULTIPLIER, MAXSIMMULTIPLIER);
	//}}AFX_DATA_MAP
}


BEGIN_MESSAGE_MAP(SSimControl, CDialog)
	//{{AFX_MSG_MAP(SSimControl)
	ON_BN_CLICKED(ID_HIDE, OnHide)
	ON_WM_HSCROLL()
	ON_EN_KILLFOCUS(IDC_SIMULATIONSPEED, OnKillfocusSimulationspeed)
	ON_EN_KILLFOCUS(IDC_RENDERSPEED, OnKillfocusRenderspeed)
	ON_BN_CLICKED(ID_DEFAULT, OnDefault)
	ON_BN_CLICKED(IDC_RSENSORS, OnRsensors)
	ON_EN_KILLFOCUS(IDC_SPEEDOFSOUND, OnKillfocusSpeedofsound)
	ON_EN_KILLFOCUS(IDC_SONARSTREAMANGLE, OnKillfocusSonarstreamangle)
	ON_EN_KILLFOCUS(IDC_SONARBEAMANGLE, OnKillfocusSonarbeamangle)
	ON_BN_CLICKED(IDC_RSONARPASTCOLLISIONS, OnRsonarpastcollisions)
	ON_BN_CLICKED(IDC_RSONARPASTBEAMS, OnRsonarpastbeams)
	ON_EN_KILLFOCUS(IDC_NSonarPastBeams, OnKillfocusNSonarPastBeams)
	ON_BN_CLICKED(IDC_FOLLOWMODEL, OnFollowmodel)
	ON_BN_CLICKED(IDC_EXTRAFLIPPING, OnExtraflipping)
	ON_EN_KILLFOCUS(IDC_SONARMAXDISTANCE, OnKillfocusSonarmaxdistance)
	ON_NOTIFY(UDN_DELTAPOS, IDC_SPINIR, OnDeltaposSpinir)
	ON_EN_KILLFOCUS(IDC_SIMMULTIPLIER, OnKillfocusSimmultiplier)
	//}}AFX_MSG_MAP
	ON_MESSAGE(WM_SPEEDUPSIM,OnSpeedUpSim)
	ON_MESSAGE(WM_SLOWDOWNSIM,OnSlowDownSim)
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// SSimControl message handlers


// Used for Modeless operation
BOOL SSimControl::Create()
{
    return CDialog::Create(IDD, m_pParent);
}

void SSimControl::OnHide() 
{


	ShowWindow(SW_HIDE);
    // need to deactivate window so the parent could get the focus
    EnableWindow(false);
    ::SendMessage(m_pParent->m_hWnd,WM_USER_SET_FOCUS,0,0);    
 
	
}




BOOL SSimControl::PreTranslateMessage(MSG* pMsg) 
{
	// TODO: Add your specialized code here and/or call the base class


     // disable the escape key
    BOOL bHandleNow = FALSE;

    switch (pMsg->message)
    {
    case WM_KEYDOWN:
        switch (pMsg->wParam)
        {
        case VK_UP:
        case VK_DOWN:
        case VK_LEFT:
        case VK_DELETE:
        case 'v':
            OnHide();
        case 'V':            
            OnHide();
        // disable the enter key
        case 13:
            SetFocus();
            return true;
        }
        if (bHandleNow)
            OnKeyDown(pMsg->wParam, LOWORD(pMsg 
                ->lParam), HIWORD(pMsg->lParam));
        break;
    }

	return CDialog::PreTranslateMessage(pMsg);
}

void SSimControl::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) 
{
	// TODO: Add your message handler code here and/or call default
    int SimID = m_SimulationSpeedSldr.GetDlgCtrlID();
    int RenderID = m_RenderSpeedSldr.GetDlgCtrlID();

    int ScrollBarID = pScrollBar->GetDlgCtrlID();

    if (ScrollBarID == SimID)
    {
        // its the simulation slider, update edit box
        
        m_SimulationSpeed = SimulationTickstoInt(m_SimulationSpeedSldr.GetPos());
        ActualSimSpeed = m_SimulationSpeed;
        UpdateData(false);
        SendUpdateMessage();
              
    }
    else if (ScrollBarID == RenderID)
    {
        // its the render slider, update edit box
        m_RenderSpeed = RenderTickstoInt(m_RenderSpeedSldr.GetPos());
        ActualRenderSpeed = m_RenderSpeed;
        UpdateData(false);    
        SendUpdateMessage();
    }
	
	CDialog::OnHScroll(nSBCode, nPos, pScrollBar);
}

BOOL SSimControl::OnInitDialog() 
{
	CDialog::OnInitDialog();

    SetSliderDefaults(); 
    
    m_IRSpin.SetBuddy(GetDlgItem(IDC_IRNONIDEALITY));
        
   
	
	return TRUE;  // return TRUE unless you set the focus to a control
	              // EXCEPTION: OCX Property Pages should return FALSE
}

// coverts the number (inside the range of the slider) to its "tick" position
int SSimControl::RenderInttoTicks(int number)
{
    float Range = MAXRENDERSPEED - MINRENDERSPEED;
    return (int)(SLIDERRANGE*number/Range);
}

// converts the "tick" position, to the number it represents
int SSimControl::RenderTickstoInt(int Position)
{
    float Range = MAXRENDERSPEED - MINRENDERSPEED;
    return (int)(MINRENDERSPEED+Position*Range/SLIDERRANGE);
}

// coverts the number (inside the range of the slider) to its "tick" position
int SSimControl::SimulationInttoTicks(int number)
{
    float Range = (MAXSIMSPEED - MINSIMSPEED);
    return (int)(SLIDERRANGE*number/Range);
}

// converts the "tick" position, to the number it represents
int SSimControl::SimulationTickstoInt(int Position)
{
    float Range = (MAXSIMSPEED - MINSIMSPEED);
    return (int)(MINSIMSPEED+Position*Range/SLIDERRANGE);
}

void SSimControl::SetSliderDefaults()
{
     // set up the simulation speed slider
    m_SimulationSpeedSldr.SetRange(0,SLIDERRANGE,false);
	m_SimulationSpeedSldr.SetPos(SimulationInttoTicks(DEFAULTSIM));
    m_SimulationSpeedSldr.SetTicFreq(SLIDERRANGE/5);
    ActualSimSpeed = m_SimulationSpeed = DEFAULTSIM;
	ActualSimMultiplier = m_SimMultiplier = DEFAULTSIMMULTIPLIER;
   

    // set up the render speed slider
    m_RenderSpeedSldr.SetRange(0,SLIDERRANGE,false);
	m_RenderSpeedSldr.SetPos(RenderInttoTicks(DEFAULTRENDER));
    m_RenderSpeedSldr.SetTicFreq(SLIDERRANGE/5);
    ActualRenderSpeed = m_RenderSpeed = DEFAULTRENDER;

    ActualSpeedofSound = m_SpeedOfSound = DEFAULTSPEEDOFSOUND;
    ActualStreamAngle = m_SonarStreamAngle = DEFAULTSONARSTREAMANGLE;
    ActualBeamAngle = m_SonarBeamAngle = DEFAULTSONARBEAMANGLE;
    ActualNRenderPastBeams = m_NSonarPastBeams = DEFAULTNPASTBEAMS;
    ActualMaximumSonarDistance = m_SonarMaxDistance = DEFAULTMAXSONARDISTANCE;

    m_RSonarPastBeams = false;
    m_RSonarPastCollisions = false;
    m_RealSensorScale = true;
    m_FollowModel = true;
    m_ExtraFlipping = true;

    m_IRNonIdeality = ActualIRNonIdeality = DEFAULTIRNONIDEALITY;


    UpdateData(false);

}

// The Simulation speed edit box may have been updated. Check it out
void SSimControl::OnKillfocusSimulationspeed() 
{
	UpdateData(true);
    // only if valid
    
    if ((m_SimulationSpeed <= MAXSIMSPEED) && (m_SimulationSpeed >=MINSIMSPEED))
    {
        ActualSimSpeed = m_SimulationSpeed;
        int Position = SimulationInttoTicks(m_SimulationSpeed);	    
        m_SimulationSpeedSldr.SetPos(Position);	
        SendUpdateMessage();
    }
    else
    {
        // reset to a valid speed
        m_SimulationSpeed = ActualSimSpeed;
        UpdateData(false);

    }

	
}



void SSimControl::OnKillfocusRenderspeed() 
{
	UpdateData(true);
    // only if valid
    
    if ((m_RenderSpeed <= MAXRENDERSPEED) && (m_RenderSpeed >=MINRENDERSPEED))
    {
        ActualRenderSpeed = m_RenderSpeed;
        int Position = RenderInttoTicks(m_RenderSpeed);	    
        m_RenderSpeedSldr.SetPos(Position);	
        SendUpdateMessage();
    }
    else
    {
        // reset to a valid speed
        m_RenderSpeed = ActualRenderSpeed;
        UpdateData(false);

    }
	
}

// sends a message to the parent telling it what changes occured
void SSimControl::SendUpdateMessage()
{
    SIMCONTROLMESSAGE Message;
    // rendering/simulation speed
    Message.ActualRenderSpeed = ActualRenderSpeed;
    Message.ActualSimSpeed = ActualSimSpeed;
	Message.ActualSimMultiplier = ActualSimMultiplier;
   
    // sonar options
    Message.SonarSpeedofSound = ActualSpeedofSound;
    Message.SonarStreamAngle = ActualStreamAngle;
    Message.SonarBeamAngle = ActualBeamAngle;
    Message.RenderPastSonarBeams = m_RSonarPastBeams;
    Message.RenderPastSonarCollisions = m_RSonarPastCollisions;
    Message.NumberofPastSonarCollisions = ActualNRenderPastBeams;
    Message.SonarMaximumDistance = ActualMaximumSonarDistance;

    // rendering options
    Message.FollowModel = m_FollowModel;
    Message.RealRenderingScale = m_RealSensorScale;
    Message.ExtraSonarFlipping = m_ExtraFlipping;

    // IR options
    Message.IRNonIdeality = ActualIRNonIdeality;

    ::SendMessage(m_pParent->m_hWnd,WM_SIMOPTIONS,(WPARAM )&Message, NULL);
    

}

void SSimControl::OnDefault() 
{
	SetSliderDefaults();
    SendUpdateMessage();
	
}

void SSimControl::OnRsensors() 
{
	UpdateData(true);
    SendUpdateMessage();
	
}

void SSimControl::OnKillfocusSpeedofsound() 
{
	UpdateData(true);
    // only if valid
    
    if ((m_SpeedOfSound <= MAXSPEEDOFSOUND) && (m_SpeedOfSound >=MINSPEEDOFSOUND))
    {
        ActualSpeedofSound = m_SpeedOfSound;       
        SendUpdateMessage();
    }
    else
    {
        // reset to a valid speed
        m_SpeedOfSound = ActualSpeedofSound;
        UpdateData(false);

    }
	
}

void SSimControl::OnKillfocusSonarstreamangle() 
{
	UpdateData(true);
    // only if valid
    
    if ((m_SonarStreamAngle <= MAXSTREAMANGLE) && (m_SonarStreamAngle >=MINSTREAMANGLE))
    {
        ActualStreamAngle = m_SonarStreamAngle;       
        SendUpdateMessage();
    }
    else
    {
        // reset to a valid speed
        m_SonarStreamAngle = ActualSpeedofSound;
        UpdateData(false);

    }
	
}

void SSimControl::OnKillfocusSonarbeamangle() 
{
	UpdateData(true);
    // only if valid
    
    if ((m_SonarBeamAngle <= MAXSONARBEAMANGLE) && (m_SonarBeamAngle >=MINSONARBEAMANGLE))
    {
        ActualBeamAngle = m_SonarBeamAngle;       
        SendUpdateMessage();
    }
    else
    {
        // reset to a valid speed
        m_SonarBeamAngle = ActualBeamAngle;
        UpdateData(false);

    }
	
}

void SSimControl::OnRsonarpastcollisions() 
{
	UpdateData(true);
    SendUpdateMessage();
	
}

void SSimControl::OnRsonarpastbeams() 
{
	UpdateData(true);
    SendUpdateMessage();
	
}

void SSimControl::OnKillfocusNSonarPastBeams() 
{
	UpdateData(true);
    // only if valid
    
    if ((m_NSonarPastBeams <= MAXNPASTBEAMS) && (m_NSonarPastBeams >=MINNPASTBEAMS))
    {
        ActualNRenderPastBeams = m_NSonarPastBeams;       
        SendUpdateMessage();
    }
    else
    {
        // reset to a valid speed
        m_NSonarPastBeams = ActualNRenderPastBeams;
        UpdateData(false);

    }
	
}

void SSimControl::OnFollowmodel() 
{
	UpdateData(true);
    SendUpdateMessage();	
}

void SSimControl::OnExtraflipping() 
{
	UpdateData(true);
    SendUpdateMessage();	
}

void SSimControl::OnKillfocusSonarmaxdistance() 
{
UpdateData(true);
    // only if valid
    
    if ((m_SonarMaxDistance <= MAXMAXSONARDISTANCE) && (m_SonarMaxDistance >= MINMAXSONARDISTANCE))
    {
        ActualMaximumSonarDistance  = m_SonarMaxDistance;       
        SendUpdateMessage();
    }
    else
    {
        // reset to a valid speed
        m_SonarMaxDistance = ActualMaximumSonarDistance;
        UpdateData(false);

    }
	
}

void SSimControl::OnDeltaposSpinir(NMHDR* pNMHDR, LRESULT* pResult) 
{
	NM_UPDOWN* pNMUpDown = (NM_UPDOWN*)pNMHDR;
    // TODO: Add your control notification handler code here

    UpdateData(true);
    // scroll up -1, +1 scroll down
    m_IRNonIdeality += -pNMUpDown->iDelta;

    if (m_IRNonIdeality < MINIRNONIDEALITY)
    {
        m_IRNonIdeality = ActualIRNonIdeality;
    }
    else if (m_IRNonIdeality > MAXIRNONIDEALITY)
    {
        m_IRNonIdeality = ActualIRNonIdeality;
    }

    ActualIRNonIdeality = m_IRNonIdeality;

    UpdateData(false);
    SendUpdateMessage();    
	
	*pResult = 0;
}

void SSimControl::OnKillfocusSimmultiplier() 
{
	UpdateData(true);
    // only if valid
    
    if ((m_SimMultiplier <= MAXSIMMULTIPLIER) && (m_SimMultiplier >=MINSIMMULTIPLIER))
    {
        ActualSimMultiplier = m_SimMultiplier;

		// update the simulation speed accordnigly
		m_SimulationSpeed = ActualSimSpeed = (int)(DEFAULTSIM*ActualSimMultiplier);
        int Position = SimulationInttoTicks(m_SimulationSpeed);	    
        m_SimulationSpeedSldr.SetPos(Position);	
		UpdateData(false);
        SendUpdateMessage();
    }
    else
    {
        // reset to a valid speed
        m_SimMultiplier = ActualSimMultiplier;
        UpdateData(false);

    }
}

LRESULT SSimControl::OnSlowDownSim(WPARAM, LPARAM)
{
	if (m_SimMultiplier > 1)
		m_SimMultiplier--;
	else 
		m_SimMultiplier -= 0.1f;

	UpdateData(false);
	OnKillfocusSimmultiplier();
	return 0;

}

LRESULT SSimControl::OnSpeedUpSim(WPARAM, LPARAM)
{
	if (m_SimMultiplier >= 1)
		m_SimMultiplier++;
	else 
		m_SimMultiplier += 0.1f;

	UpdateData(false);
	OnKillfocusSimmultiplier();
	return 0;

}
