/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.apache.shardingsphere.shadow.rewrite.token.generator.impl;

import org.apache.shardingsphere.infra.rewrite.sql.token.generator.CollectionSQLTokenGenerator;
import org.apache.shardingsphere.infra.rewrite.sql.token.pojo.generic.RemoveToken;
import org.apache.shardingsphere.shadow.rewrite.token.generator.BaseShadowSQLTokenGenerator;
import org.apache.shardingsphere.infra.binder.statement.SQLStatementContext;
import org.apache.shardingsphere.infra.binder.statement.dml.InsertStatementContext;
import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.column.ColumnSegment;
import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.column.InsertColumnsSegment;
import org.apache.shardingsphere.sql.parser.sql.common.statement.dml.InsertStatement;

import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import java.util.Optional;

/**
 * Remove shadow column token generator.
 */
public final class ShadowInsertColumnTokenGenerator extends BaseShadowSQLTokenGenerator implements CollectionSQLTokenGenerator<InsertStatementContext> {
    
    @Override
    protected boolean isGenerateSQLTokenForShadow(final SQLStatementContext sqlStatementContext) {
        return sqlStatementContext instanceof InsertStatementContext && isContainShadowColumn(((InsertStatementContext) sqlStatementContext).getSqlStatement());
    }
    
    private boolean isContainShadowColumn(final InsertStatement sqlStatement) {
        Optional<InsertColumnsSegment> insertColumnsSegment = sqlStatement.getInsertColumns();
        return insertColumnsSegment.isPresent() && !insertColumnsSegment.get().getColumns().isEmpty();
    }
    
    @Override
    public Collection<RemoveToken> generateSQLTokens(final InsertStatementContext insertStatementContext) {
        Optional<InsertColumnsSegment> sqlSegment = insertStatementContext.getSqlStatement().getInsertColumns();
        Collection<RemoveToken> result = new LinkedList<>();
        sqlSegment.ifPresent(insertColumnsSegment -> generateRemoveTokenForShadow(insertColumnsSegment, result));
        return result;
    }
    
    private void generateRemoveTokenForShadow(final InsertColumnsSegment insertColumnsSegment, final Collection<RemoveToken> removeTokens) {
        List<ColumnSegment> columnSegments = (LinkedList<ColumnSegment>) insertColumnsSegment.getColumns();
        String shadowColumn = getShadowColumn();
        for (int i = 0; i < columnSegments.size(); i++) {
            ColumnSegment columnSegment = columnSegments.get(i);
            if (shadowColumn.equals(columnSegment.getIdentifier().getValue())) {
                RemoveToken removeToken = i == 0 ? new RemoveToken(columnSegments.get(i).getStartIndex(), columnSegments.get(i + 1).getStartIndex() - 1)
                        : new RemoveToken(columnSegments.get(i - 1).getStopIndex() + 1, columnSegments.get(i).getStopIndex());
                removeTokens.add(removeToken);
            }
        }
    }
}

@@ -3217,57 +3217,22 @@
     
-for (
 int i
+ndex
  = 0;
- i %3C columnSegments.size(); i++) %7B
 %0A   
@@ -3236,20 +3236,21 @@
         
-    
+for (
 ColumnSe
@@ -3259,23 +3259,14 @@
 ent 
-columnSegment =
+each :
  col
@@ -3280,16 +3280,11 @@
 ents
-.get(i);
+) %7B
 %0A   
@@ -3316,29 +3316,20 @@
 .equals(
-columnSegment
+each
 .getIden
@@ -3372,40 +3372,283 @@
     
-RemoveToken removeToken = i == 0
+removeTokens.add(createShadowColumnRemoveToken(columnSegments, index));%0A            %7D%0A            index++;%0A        %7D%0A    %7D%0A%0A    private RemoveToken createShadowColumnRemoveToken(final List%3CColumnSegment%3E columnSegments, final int index) %7B%0A        return isFirstElement(index)
  ? n
@@ -3678,24 +3678,28 @@
 gments.get(i
+ndex
 ).getStartIn
@@ -3725,16 +3725,20 @@
 ts.get(i
+ndex
  + 1).ge
@@ -3772,24 +3772,16 @@
         
-   
-     
 : new Re
@@ -3810,16 +3810,20 @@
 ts.get(i
+ndex
  - 1).ge
@@ -3860,16 +3860,20 @@
 ts.get(i
+ndex
 ).getSto
@@ -3891,74 +3891,95 @@
     
- 
+%7D%0A
     
+%0A
     
-   removeTokens.add(removeToken);%0A         
+private boolean isFirstElement(final int count) %7B%0A
    
-%7D%0A
      
-   %7D
+return count == 0;
 %0A   

Refactor use iterator to visit LinkedList. (#11829)