using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using StarEngine;
using Ruby;
using VALUE = System.Int32;
using StarEngine.Core;

namespace StarEngine.Ruby
{
    public partial class RubyInterpreter
    {
        private void InitializeAudioModule()
        {
            VALUE mAudio = SERubyConsts.ForName("Audio");

            RUBY.rb_define_singleton_method(mAudio, "__cs_play_bgm__", this.mAudio_cs_play_bgm);
            RUBY.rb_define_singleton_method(mAudio, "__cs_stop_bgm__", this.mAudio_cs_stop_bgm);
            RUBY.rb_define_singleton_method(mAudio, "playing_bgm?", this.mAudio_playing_bgm);
            RUBY.rb_define_singleton_method(mAudio, "bgm_volume", this.mAudio_bgm_volume);
            RUBY.rb_define_singleton_method(mAudio, "bgm_volume=", this.mAudio_bgm_volume_eq);
            RUBY.rb_define_singleton_method(mAudio, "__cs_play_se__", this.mAudio_cs_play_se);
            RUBY.rb_define_singleton_method(mAudio, "__cs_stop_all_ses__", this.mAudio_cs_stop_all_ses);
        }

        private VALUE mAudio_cs_play_bgm(VALUE self, VALUE rbPath, VALUE rbTime, VALUE rbVolume, VALUE rbLoop)
        {
            string csPath = RUBY.StringValuePtr(rbPath);
            csPath = PathExtensions.GetFullPathAndExtension(csPath);
            int csVolumeInt = (rbVolume == RUBY.Qnil) ? 255 : RUBY.NUM2INT(rbVolume);
            int csTime = (rbTime == RUBY.Qnil) ? 0 : RUBY.NUM2INT(rbTime);
            byte csVolume = (byte)Math.Max(0, Math.Min(255, csVolumeInt));
            bool csLoop = (rbLoop == RUBY.Qnil) ? true : RUBY.ToBool(rbLoop);

            try
            {
                this.GameEnvironment.Audio.PlayBgm(csPath, csTime, csVolume, csLoop);
            }
            catch (FileNotFoundException e)
            {
                RUBY.rb_raise(SERubyConsts.ForName("::Errno::ENOENT"), e.FileName);
            }
            catch (StarEngineException e)
            {
                RUBY.rb_raise(SERubyConsts.ForName("StarEngineError"), e.Message);
            }
            return RUBY.Qnil;
        }

        private VALUE mAudio_cs_stop_bgm(VALUE self, VALUE rbTime)
        {
            int csTime = (rbTime == RUBY.Qnil) ? 0 : RUBY.NUM2INT(rbTime);
            this.GameEnvironment.Audio.StopBgm(csTime);
            return RUBY.Qnil;
        }

        private VALUE mAudio_playing_bgm(VALUE self)
        {
            return this.GameEnvironment.Audio.IsPlayingBgm ? RUBY.Qtrue : RUBY.Qfalse;
        }

        private VALUE mAudio_bgm_volume(VALUE self)
        {
            return RUBY.INT2NUM(this.GameEnvironment.Audio.BgmVolume);
        }

        private VALUE mAudio_bgm_volume_eq(VALUE self, VALUE rbBgmVolume)
        {
            IAudio audio = this.GameEnvironment.Audio;
            audio.BgmVolume = (byte)Math.Min(Math.Max(RUBY.NUM2INT(rbBgmVolume), 0), 255);
            return rbBgmVolume;
        }

        private VALUE mAudio_cs_play_se(VALUE self, VALUE rbPath, VALUE rbTime, VALUE rbVolume, VALUE rbPanning)
        {
            string csPath = RUBY.StringValuePtr(rbPath);
            csPath = PathExtensions.GetFullPathAndExtension(csPath);
            int csVolumeInt = (rbVolume == RUBY.Qnil) ? 255 : RUBY.NUM2INT(rbVolume);
            byte csVolume = (byte)Math.Max(0, Math.Min(255, csVolumeInt));
            int csTime = (rbTime == RUBY.Qnil) ? 0 : RUBY.NUM2INT(rbTime);
            int csPanningInt = (rbVolume == RUBY.Qnil) ? 128 : RUBY.NUM2INT(rbPanning);
            byte csPanning = (byte)Math.Max(0, Math.Min(255, csPanningInt));

            try
            {
                this.GameEnvironment.Audio.PlaySE(csPath, csTime, csVolume, csPanning);
            }
            catch (FileNotFoundException e)
            {
                RUBY.rb_raise(SERubyConsts.ForName("::Errno::ENOENT"), e.FileName);
            }
            catch (StarEngineException e)
            {
                RUBY.rb_raise(SERubyConsts.ForName("StarEngineError"), e.Message);
            }
            return RUBY.Qnil;
        }

        private VALUE mAudio_cs_stop_all_ses(VALUE self, VALUE rbTime)
        {
            int csTime = (rbTime == RUBY.Qnil) ? 0 : RUBY.NUM2INT(rbTime);
            this.GameEnvironment.Audio.StopAllSEs(csTime);
            return RUBY.Qnil;
        }
    }
}
