using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace MojaDrugaGra
{
    class Sfera : DrawableGameComponent
    {
        GraphicsDevice gd;
        BasicEffect efekt;
        VertexBuffer buforWerteksów;
        IndexBuffer buforIndeksów;
        private float promień;
        private int liczbaSekcjiNaRównoleżnikach, liczbaSekcjiNaPołudnikach;
                         
        public Matrix MacierzSwiata
        {
            get => efekt.World;
            set => efekt.World = value;          
        }
        public Matrix MacierzWidoku
        {
            get => efekt.View;
            set => efekt.View = value;
        }
        public bool TeksturowanieWłączone
        {
            get => efekt.TextureEnabled;
            set => efekt.TextureEnabled = value;
        }
        public Texture2D Tekstura
        {
            get => efekt.Texture;
            set => efekt.Texture = value;
        }
        
        public Sfera(Game game, BasicEffect efekt, float promień,
                    int liczbeSekcjiNaRównoleżnikach,
                    int liczbaSekcjiNaPołudnikach, Color kolor) : base(game)
        {
            gd = game.GraphicsDevice;
            this.efekt = (BasicEffect)efekt.Clone();
            this.promień = promień;
            this.liczbaSekcjiNaRównoleżnikach = liczbeSekcjiNaRównoleżnikach;
            this.liczbaSekcjiNaPołudnikach = liczbaSekcjiNaPołudnikach;
            //na czas przygotowywania
            gd.RasterizerState = RasterizerState.CullNone;
            
                this.efekt = (BasicEffect)efekt.Clone();
    this.promień = promień;
    this.liczbaSekcjiNaRównoleżnikach = liczbeSekcjiNaRównoleżnikach;
    this.liczbaSekcjiNaPołudnikach = liczbaSekcjiNaPołudnikach;
    //na czas przygotowywania
    gd.RasterizerState = RasterizerState.CullNone;

    int całkowitaLiczbaWerteksów =
        (liczbeSekcjiNaRównoleżnikach + 1) *
        (liczbaSekcjiNaPołudnikach + 1);
    List<VertexPositionColorNormalTexture> listaWerteksów =
        new List<VertexPositionColorNormalTexture>(
        całkowitaLiczbaWerteksów);
    double przyrostKątaTheta = Math.PI / liczbaSekcjiNaPołudnikach;
    double przyrostKątaPhi = 2 * Math.PI /
        liczbeSekcjiNaRównoleżnikach;
    //tablica werteksów
    for (int i = 0; i <= liczbaSekcjiNaPołudnikach; i++)
    {
        double kątTheta = i * przyrostKątaTheta;
        float _wysokość = (float)(promień * Math.Cos(kątTheta));
        float _promień = (float)(promień * Math.Sin(kątTheta));
        for (int j = 0; j <= liczbeSekcjiNaRównoleżnikach; j++)
        {
            double kątPhi = j * przyrostKątaPhi;
            int indeks = j + i *(liczbeSekcjiNaRównoleżnikach+1);
            Vector3 położenie = new Vector3(
                _promień * (float)Math.Cos(kątPhi),
                -_promień * (float)Math.Sin(kątPhi),
                _wysokość);
            //Vector3 normalna = Vector3.Up; //prowizoryczne
            Vector3 normalna = Vector3.Normalize(położenie); //prowizoryczne
            //Vector2 współrzędneTeksturowania = Vector2.Zero; //prowizoryczne
            Vector2 współrzędneTeksturowania =
                new Vector2(
                    (float)(1 - kątPhi / (2 * Math.PI)),
                    (float)(kątTheta / Math.PI));
            listaWerteksów.Add(
                new VertexPositionColorNormalTexture(
                położenie, kolor, normalna,
                współrzędneTeksturowania));
        }
    }
    //bufor werteksów
    buforWerteksów = new VertexBuffer(
        gd, VertexPositionColorNormalTexture.VertexDeclaration,
        listaWerteksów.Count, BufferUsage.WriteOnly);
    buforWerteksów.SetData<VertexPositionColorNormalTexture>(
        listaWerteksów.ToArray());
    //tablica indeksów
    int liczbaIndeksówWPaśmie = 2*(liczbaSekcjiNaPołudnikach+ 1);
    int całkowitaLiczbaIndeksów = liczbaIndeksówWPaśmie *
        liczbaSekcjiNaPołudnikach;
    List<int> listaIndeksów = new List<int>(całkowitaLiczbaIndeksów);
    for (int i = 0; i < całkowitaLiczbaIndeksów / 2; i++)
    {
        listaIndeksów.Add(i);
        listaIndeksów.Add(i+(liczbeSekcjiNaRównoleżnikach+1));
    }
    //bufor indeksów
    buforIndeksów = new IndexBuffer(
        gd, IndexElementSize.ThirtyTwoBits,
        listaIndeksów.Count, BufferUsage.WriteOnly);
    buforIndeksów.SetData<int>(listaIndeksów.ToArray());
        }

        public override void Draw(GameTime gameTime)
        {
            gd.SetVertexBuffer(buforWerteksów);
    gd.Indices = buforIndeksów;
    int liczbaWerteksówWPaśmie=(liczbaSekcjiNaRównoleżnikach+1)* 2;
    foreach (EffectPass pass in efekt.CurrentTechnique.Passes)
    {
        pass.Apply();
        for (int i = 0; i < liczbaSekcjiNaPołudnikach; i++)
        {
            gd.DrawIndexedPrimitives(
                PrimitiveType.TriangleStrip,
                0, 0,
                liczbaWerteksówWPaśmie,
                i * liczbaWerteksówWPaśmie,
                liczbaSekcjiNaRównoleżnikach * 2);
        }
    }
    base.Draw(gameTime);

        }
    }
}
